summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/SimpleUDPClientAndServer.c397
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/TCPEchoClient_SingleTasks.c400
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/include/SimpleUDPClientAndServer.h75
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/include/TCPEchoClient_SingleTasks.h82
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOSConfig.h261
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOSIPConfig.h349
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOS_Plus_TCP_Minimal.sln23
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOS_Plus_TCP_Minimal.suobin0 -> 29696 bytes
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/ReadMe.txt34
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/Read_Me_Build_Instructions.url6
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WIN32.vcxproj196
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WIN32.vcxproj.filters174
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/Packet32.h359
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/PacketData.h267
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/Win32-Extensions.h114
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/arch.c378
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/bittypes.h137
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/ip6_misc.h163
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/netif.h94
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-bpf.h47
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-namedb.h42
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-stdinc.h93
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap.h45
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/bluetooth.h48
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/bpf.h934
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/namedb.h89
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/pcap.h407
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/sll.h129
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/usb.h90
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/vlan.h46
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/remote-ext.h444
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/wpcap.libbin0 -> 19320 bytes
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/demo_logging.c568
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/demo_logging.h89
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/main.c380
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/printf-stdarg.c667
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/.cproject43
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/CLI-commands.c39
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/FreeRTOSConfig.h10
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/trcConfig.h521
-rw-r--r--FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/trcSnapshotConfig.h472
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c682
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c1015
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c1228
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c2205
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c3644
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c231
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c3359
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c2009
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c420
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt131
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/ReadMe.url5
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h577
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h173
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h119
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h165
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h350
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h840
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h420
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h288
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h112
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h253
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h88
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h122
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h225
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h102
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h76
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c455
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c410
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h78
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h80
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h79
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h81
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h80
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h79
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h86
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h85
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c680
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/component/gmac.h746
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.c454
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.h281
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c945
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.h1346
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/instance/gmac.h1349
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c293
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c1100
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/ReadMe.txt3
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/README_DRIVER_DISCLAIMER.txt10
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c144
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c1458
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c173
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c631
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c430
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt25
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h144
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c657
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c243
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.h39
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c585
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_topology.h46
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c1304
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/Common/FreeRTOS_TCP_server.c382
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_commands.c106
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_server.c2669
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_commands.c103
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_server.c455
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/NTP/NTPDemo.c472
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_FTP_commands.h165
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_HTTP_commands.h99
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_TCP_server.h157
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_server_private.h217
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPClient.h71
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPDemo.h11
-rw-r--r--FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/readme.txt18
114 files changed, 46629 insertions, 446 deletions
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/SimpleUDPClientAndServer.c b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/SimpleUDPClientAndServer.c
new file mode 100644
index 000000000..9e67c9a7a
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/SimpleUDPClientAndServer.c
@@ -0,0 +1,397 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * Creates two transmitting tasks and two receiving tasks. The transmitting
+ * tasks send values that are received by the receiving tasks. One set of tasks
+ * uses the standard API. The other set of tasks uses the zero copy API.
+ *
+ * See the following web page for essential demo usage and configuration
+ * details:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+
+#define simpTINY_DELAY ( ( TickType_t ) 2 )
+
+/*
+ * Uses a socket to send data without using the zero copy option.
+ * prvSimpleServerTask() will receive the data.
+ */
+static void prvSimpleClientTask( void *pvParameters );
+
+/*
+ * Uses a socket to receive the data sent by the prvSimpleClientTask() task.
+ * Does not use the zero copy option.
+ */
+static void prvSimpleServerTask( void *pvParameters );
+
+/*
+ * Uses a socket to send data using the zero copy option.
+ * prvSimpleZeroCopyServerTask() will receive the data.
+ */
+static void prvSimpleZeroCopyUDPClientTask( void *pvParameters );
+
+/*
+ * Uses a socket to receive the data sent by the prvSimpleZeroCopyUDPClientTask()
+ * task. Uses the zero copy option.
+ */
+static void prvSimpleZeroCopyServerTask( void *pvParameters );
+
+/*-----------------------------------------------------------*/
+
+void vStartSimpleUDPClientServerTasks( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority )
+{
+ /* Create the client and server tasks that do not use the zero copy
+ interface. */
+ xTaskCreate( prvSimpleClientTask, "SimpCpyClnt", usStackSize, ( void * ) ulPort, uxPriority, NULL );
+ xTaskCreate( prvSimpleServerTask, "SimpCpySrv", usStackSize, ( void * ) ulPort, uxPriority + 1, NULL );
+
+ /* Create the client and server tasks that do use the zero copy interface. */
+ xTaskCreate( prvSimpleZeroCopyUDPClientTask, "SimpZCpyClnt", usStackSize, ( void * ) ( ulPort + 1 ), uxPriority, NULL );
+ xTaskCreate( prvSimpleZeroCopyServerTask, "SimpZCpySrv", usStackSize, ( void * ) ( ulPort + 1 ), uxPriority + 1, NULL );
+}
+/*-----------------------------------------------------------*/
+
+static void prvSimpleClientTask( void *pvParameters )
+{
+Socket_t xClientSocket;
+struct freertos_sockaddr xDestinationAddress;
+uint8_t cString[ 50 ];
+BaseType_t lReturned;
+uint32_t ulCount = 0UL, ulIPAddress;
+const uint32_t ulLoopsPerSocket = 10UL;
+const TickType_t x150ms = 150UL / portTICK_PERIOD_MS;
+
+ /* Remove compiler warning about unused parameters. */
+ ( void ) pvParameters;
+
+ /* It is assumed that this task is not created until the network is up,
+ so the IP address can be obtained immediately. store the IP address being
+ used in ulIPAddress. This is done so the socket can send to a different
+ port on the same IP address. */
+ FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL );
+
+ /* This test sends to itself, so data sent from here is received by a server
+ socket on the same IP address. Setup the freertos_sockaddr structure with
+ this nodes IP address, and the port number being sent to. The strange
+ casting is to try and remove compiler warnings on 32 bit machines. */
+ xDestinationAddress.sin_addr = ulIPAddress;
+ xDestinationAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL;
+ xDestinationAddress.sin_port = FreeRTOS_htons( xDestinationAddress.sin_port );
+
+ for( ;; )
+ {
+ /* Create the socket. */
+ xClientSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
+ configASSERT( xClientSocket != FREERTOS_INVALID_SOCKET );
+
+ /* The count is used to differentiate between different messages sent to
+ the server, and to break out of the do while loop below. */
+ ulCount = 0UL;
+
+ do
+ {
+ /* Create the string that is sent to the server. */
+ sprintf( ( char * ) cString, "Server received (not zero copy): Message number %lu\r\n", ulCount );
+
+ /* Send the string to the socket. ulFlags is set to 0, so the zero
+ copy option is not selected. That means the data from cString[] is
+ copied into a network buffer inside FreeRTOS_sendto(), and cString[]
+ can be reused as soon as FreeRTOS_sendto() has returned. */
+ lReturned = FreeRTOS_sendto( xClientSocket, ( void * ) cString, strlen( ( const char * ) cString ), 0, &xDestinationAddress, sizeof( xDestinationAddress ) );
+
+ ulCount++;
+
+ } while( ( lReturned != FREERTOS_SOCKET_ERROR ) && ( ulCount < ulLoopsPerSocket ) );
+
+ FreeRTOS_closesocket( xClientSocket );
+
+ /* A short delay to prevent the messages printed by the server task
+ scrolling off the screen too quickly, and to prevent reduce the network
+ loading. */
+ vTaskDelay( x150ms );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvSimpleServerTask( void *pvParameters )
+{
+int32_t lBytes;
+uint8_t cReceivedString[ 60 ];
+struct freertos_sockaddr xClient, xBindAddress;
+uint32_t xClientLength = sizeof( xClient );
+Socket_t xListeningSocket;
+
+ /* Just to prevent compiler warnings. */
+ ( void ) pvParameters;
+
+ /* Attempt to open the socket. */
+ xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
+ configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );
+
+ /* This test receives data sent from a different port on the same IP
+ address. Configure the freertos_sockaddr structure with the address being
+ bound to. The strange casting is to try and remove compiler warnings on 32
+ bit machines. Note that this task is only created after the network is up,
+ so the IP address is valid here. */
+ xBindAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL;
+ xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );
+
+ /* Bind the socket to the port that the client task will send to. */
+ FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );
+
+ for( ;; )
+ {
+ /* Zero out the receive array so there is NULL at the end of the string
+ when it is printed out. */
+ memset( cReceivedString, 0x00, sizeof( cReceivedString ) );
+
+ /* Receive data on the socket. ulFlags is zero, so the zero copy option
+ is not set and the received data is copied into the buffer pointed to by
+ cReceivedString. By default the block time is portMAX_DELAY.
+ xClientLength is not actually used by FreeRTOS_recvfrom(), but is set
+ appropriately in case future versions do use it. */
+ lBytes = FreeRTOS_recvfrom( xListeningSocket, cReceivedString, sizeof( cReceivedString ), 0, &xClient, &xClientLength );
+
+ /* Error check. */
+ configASSERT( lBytes == ( BaseType_t ) strlen( ( const char * ) cReceivedString ) );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvSimpleZeroCopyUDPClientTask( void *pvParameters )
+{
+Socket_t xClientSocket;
+uint8_t *pucUDPPayloadBuffer;
+struct freertos_sockaddr xDestinationAddress;
+BaseType_t lReturned;
+uint32_t ulCount = 0UL, ulIPAddress;
+const uint32_t ulLoopsPerSocket = 10UL;
+const char *pcStringToSend = "Server received (using zero copy): Message number ";
+const TickType_t x150ms = 150UL / portTICK_PERIOD_MS;
+/* 15 is added to ensure the number, \r\n and terminating zero fit. */
+const size_t xStringLength = strlen( pcStringToSend ) + 15;
+
+ /* Remove compiler warning about unused parameters. */
+ ( void ) pvParameters;
+
+ /* It is assumed that this task is not created until the network is up,
+ so the IP address can be obtained immediately. store the IP address being
+ used in ulIPAddress. This is done so the socket can send to a different
+ port on the same IP address. */
+ FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL );
+
+ /* This test sends to itself, so data sent from here is received by a server
+ socket on the same IP address. Setup the freertos_sockaddr structure with
+ this nodes IP address, and the port number being sent to. The strange
+ casting is to try and remove compiler warnings on 32 bit machines. */
+ xDestinationAddress.sin_addr = ulIPAddress;
+ xDestinationAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL;
+ xDestinationAddress.sin_port = FreeRTOS_htons( xDestinationAddress.sin_port );
+
+ for( ;; )
+ {
+ /* Create the socket. */
+ xClientSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
+ configASSERT( xClientSocket != FREERTOS_INVALID_SOCKET );
+
+ /* The count is used to differentiate between different messages sent to
+ the server, and to break out of the do while loop below. */
+ ulCount = 0UL;
+
+ do
+ {
+ /* This task is going to send using the zero copy interface. The
+ data being sent is therefore written directly into a buffer that is
+ passed into, rather than copied into, the FreeRTOS_sendto()
+ function.
+
+ First obtain a buffer of adequate length from the IP stack into which
+ the string will be written. Although a max delay is used, the actual
+ delay will be capped to ipconfigMAX_SEND_BLOCK_TIME_TICKS, hence
+ the do while loop is used to ensure a buffer is obtained. */
+ do
+ {
+ } while( ( pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xStringLength, portMAX_DELAY ) ) == NULL );
+
+ /* A buffer was successfully obtained. Create the string that is
+ sent to the server. First the string is filled with zeros as this will
+ effectively be the null terminator when the string is received at the other
+ end. Note that the string is being written directly into the buffer
+ obtained from the IP stack above. */
+ memset( ( void * ) pucUDPPayloadBuffer, 0x00, xStringLength );
+ sprintf( ( char * ) pucUDPPayloadBuffer, "%s%lu\r\n", pcStringToSend, ulCount );
+
+ /* Pass the buffer into the send function. ulFlags has the
+ FREERTOS_ZERO_COPY bit set so the IP stack will take control of the
+ buffer rather than copy data out of the buffer. */
+ lReturned = FreeRTOS_sendto( xClientSocket, /* The socket being sent to. */
+ ( void * ) pucUDPPayloadBuffer, /* A pointer to the the data being sent. */
+ strlen( ( const char * ) pucUDPPayloadBuffer ) + 1, /* The length of the data being sent - including the string's null terminator. */
+ FREERTOS_ZERO_COPY, /* ulFlags with the FREERTOS_ZERO_COPY bit set. */
+ &xDestinationAddress, /* Where the data is being sent. */
+ sizeof( xDestinationAddress ) );
+
+ if( lReturned == 0 )
+ {
+ /* The send operation failed, so this task is still responsible
+ for the buffer obtained from the IP stack. To ensure the buffer
+ is not lost it must either be used again, or, as in this case,
+ returned to the IP stack using FreeRTOS_ReleaseUDPPayloadBuffer().
+ pucUDPPayloadBuffer can be safely re-used after this call. */
+ FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );
+ }
+ else
+ {
+ /* The send was successful so the IP stack is now managing the
+ buffer pointed to by pucUDPPayloadBuffer, and the IP stack will
+ return the buffer once it has been sent. pucUDPPayloadBuffer can
+ be safely re-used. */
+ }
+
+ ulCount++;
+
+ } while( ( lReturned != FREERTOS_SOCKET_ERROR ) && ( ulCount < ulLoopsPerSocket ) );
+
+ FreeRTOS_closesocket( xClientSocket );
+
+ /* A short delay to prevent the messages scrolling off the screen too
+ quickly. */
+ vTaskDelay( x150ms );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvSimpleZeroCopyServerTask( void *pvParameters )
+{
+int32_t lBytes;
+uint8_t *pucUDPPayloadBuffer;
+struct freertos_sockaddr xClient, xBindAddress;
+uint32_t xClientLength = sizeof( xClient ), ulIPAddress;
+Socket_t xListeningSocket;
+
+ /* Just to prevent compiler warnings. */
+ ( void ) pvParameters;
+
+ /* Attempt to open the socket. */
+ xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
+ configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );
+
+ /* This test receives data sent from a different port on the same IP address.
+ Obtain the nodes IP address. Configure the freertos_sockaddr structure with
+ the address being bound to. The strange casting is to try and remove
+ compiler warnings on 32 bit machines. Note that this task is only created
+ after the network is up, so the IP address is valid here. */
+ FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL );
+ xBindAddress.sin_addr = ulIPAddress;
+ xBindAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL;
+ xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );
+
+ /* Bind the socket to the port that the client task will send to. */
+ FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );
+
+ for( ;; )
+ {
+ /* Receive data on the socket. ulFlags has the zero copy bit set
+ (FREERTOS_ZERO_COPY) indicating to the stack that a reference to the
+ received data should be passed out to this task using the second
+ parameter to the FreeRTOS_recvfrom() call. When this is done the
+ IP stack is no longer responsible for releasing the buffer, and
+ the task *must* return the buffer to the stack when it is no longer
+ needed. By default the block time is portMAX_DELAY. */
+ lBytes = FreeRTOS_recvfrom( xListeningSocket, ( void * ) &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xClient, &xClientLength );
+
+ /* Print the received characters. */
+ if( lBytes > 0 )
+ {
+ /* It is expected to receive one more byte than the string length as
+ the NULL terminator is also transmitted. */
+ configASSERT( lBytes == ( ( BaseType_t ) strlen( ( const char * ) pucUDPPayloadBuffer ) + 1 ) );
+ }
+
+ if( lBytes >= 0 )
+ {
+ /* The buffer *must* be freed once it is no longer needed. */
+ FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
+ }
+ }
+}
+
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/TCPEchoClient_SingleTasks.c b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/TCPEchoClient_SingleTasks.c
new file mode 100644
index 000000000..4ebd6e3d5
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/TCPEchoClient_SingleTasks.c
@@ -0,0 +1,400 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * A set of tasks are created that send TCP echo requests to the standard echo
+ * port (port 7) on the IP address set by the configECHO_SERVER_ADDR0 to
+ * configECHO_SERVER_ADDR3 constants, then wait for and verify the reply
+ * (another demo is avilable that demonstrates the reception being performed in
+ * a task other than that from with the request was made).
+ *
+ * See the following web page for essential demo usage and configuration
+ * details:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+
+/* Exclude the whole file if FreeRTOSIPConfig.h is configured to use UDP only. */
+#if( ipconfigUSE_TCP == 1 )
+
+/* The echo tasks create a socket, send out a number of echo requests, listen
+for the echo reply, then close the socket again before starting over. This
+delay is used between each iteration to ensure the network does not get too
+congested. */
+#define echoLOOP_DELAY ( ( TickType_t ) 150 / portTICK_PERIOD_MS )
+
+/* The echo server is assumed to be on port 7, which is the standard echo
+protocol port. */
+#define echoECHO_PORT ( 7 )
+
+/* The size of the buffers is a multiple of the MSS - the length of the data
+sent is a pseudo random size between 20 and echoBUFFER_SIZES. */
+#define echoBUFFER_SIZE_MULTIPLIER ( 3 )
+#define echoBUFFER_SIZES ( ipconfigTCP_MSS * echoBUFFER_SIZE_MULTIPLIER )
+
+/* The number of instances of the echo client task to create. */
+#define echoNUM_ECHO_CLIENTS ( 5 )
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Uses a socket to send data to, then receive data from, the standard echo
+ * port number 7.
+ */
+static void prvEchoClientTask( void *pvParameters );
+
+/*
+ * Creates a pseudo random sized buffer of data to send to the echo server.
+ */
+static BaseType_t prvCreateTxData( char *ucBuffer, uint32_t ulBufferLength );
+
+/*-----------------------------------------------------------*/
+
+/* Rx and Tx time outs are used to ensure the sockets do not wait too long for
+missing data. */
+static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 4000 );
+static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 2000 );
+
+/* Counters for each created task - for inspection only. */
+static uint32_t ulTxRxCycles[ echoNUM_ECHO_CLIENTS ] = { 0 },
+ ulTxRxFailures[ echoNUM_ECHO_CLIENTS ] = { 0 },
+ ulConnections[ echoNUM_ECHO_CLIENTS ] = { 0 };
+
+/* Rx and Tx buffers for each created task. */
+static char cTxBuffers[ echoNUM_ECHO_CLIENTS ][ echoBUFFER_SIZES ],
+ cRxBuffers[ echoNUM_ECHO_CLIENTS ][ echoBUFFER_SIZES ];
+
+/*-----------------------------------------------------------*/
+
+void vStartTCPEchoClientTasks_SingleTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority )
+{
+BaseType_t x;
+
+ /* Create the echo client tasks. */
+ for( x = 0; x < echoNUM_ECHO_CLIENTS; x++ )
+ {
+ xTaskCreate( prvEchoClientTask, /* The function that implements the task. */
+ "Echo0", /* Just a text name for the task to aid debugging. */
+ usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */
+ ( void * ) x, /* The task parameter, not used in this case. */
+ uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */
+ NULL ); /* The task handle is not used. */
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvEchoClientTask( void *pvParameters )
+{
+Socket_t xSocket;
+struct freertos_sockaddr xEchoServerAddress;
+int32_t lLoopCount = 0UL;
+const int32_t lMaxLoopCount = 1;
+volatile uint32_t ulTxCount = 0UL;
+BaseType_t xReceivedBytes, xReturned, xInstance;
+BaseType_t lTransmitted, lStringLength;
+char *pcTransmittedString, *pcReceivedString;
+WinProperties_t xWinProps;
+TickType_t xTimeOnEntering;
+
+ /* Fill in the buffer and window sizes that will be used by the socket. */
+ xWinProps.lTxBufSize = 6 * ipconfigTCP_MSS;
+ xWinProps.lTxWinSize = 3;
+ xWinProps.lRxBufSize = 6 * ipconfigTCP_MSS;
+ xWinProps.lRxWinSize = 3;
+
+ /* This task can be created a number of times. Each instance is numbered
+ to enable each instance to use a different Rx and Tx buffer. The number is
+ passed in as the task's parameter. */
+ xInstance = ( BaseType_t ) pvParameters;
+
+ /* Point to the buffers to be used by this instance of this task. */
+ pcTransmittedString = &( cTxBuffers[ xInstance ][ 0 ] );
+ pcReceivedString = &( cRxBuffers[ xInstance ][ 0 ] );
+
+ /* Echo requests are sent to the echo server. The address of the echo
+ server is configured by the constants configECHO_SERVER_ADDR0 to
+ configECHO_SERVER_ADDR3 in FreeRTOSConfig.h. */
+ xEchoServerAddress.sin_port = FreeRTOS_htons( echoECHO_PORT );
+ xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0,
+ configECHO_SERVER_ADDR1,
+ configECHO_SERVER_ADDR2,
+ configECHO_SERVER_ADDR3 );
+
+ for( ;; )
+ {
+ /* Create a TCP socket. */
+ xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
+ configASSERT( xSocket != FREERTOS_INVALID_SOCKET );
+
+ /* Set a time out so a missing reply does not cause the task to block
+ indefinitely. */
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) );
+
+ /* Set the window and buffer sizes. */
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) );
+
+ /* Connect to the echo server. */
+ if( FreeRTOS_connect( xSocket, &xEchoServerAddress, sizeof( xEchoServerAddress ) ) == 0 )
+ {
+ ulConnections[ xInstance ]++;
+
+ /* Send a number of echo requests. */
+ for( lLoopCount = 0; lLoopCount < lMaxLoopCount; lLoopCount++ )
+ {
+ /* Create the string that is sent to the echo server. */
+ lStringLength = prvCreateTxData( pcTransmittedString, echoBUFFER_SIZES );
+
+ /* Add in some unique text at the front of the string. */
+ sprintf( pcTransmittedString, "TxRx message number %u", ulTxCount );
+ ulTxCount++;
+
+ /* Send the string to the socket. */
+ lTransmitted = FreeRTOS_send( xSocket, /* The socket being sent to. */
+ ( void * ) pcTransmittedString, /* The data being sent. */
+ lStringLength, /* The length of the data being sent. */
+ 0 ); /* No flags. */
+
+ if( lTransmitted < 0 )
+ {
+ /* Error? */
+ break;
+ }
+
+ /* Clear the buffer into which the echoed string will be
+ placed. */
+ memset( ( void * ) pcReceivedString, 0x00, echoBUFFER_SIZES );
+ xReceivedBytes = 0;
+
+ /* Receive data echoed back to the socket. */
+ while( xReceivedBytes < lTransmitted )
+ {
+ xReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */
+ &( pcReceivedString[ xReceivedBytes ] ),/* The buffer into which the received data will be written. */
+ lStringLength - xReceivedBytes, /* The size of the buffer provided to receive the data. */
+ 0 ); /* No flags. */
+
+ if( xReturned < 0 )
+ {
+ /* Error occurred. Latch it so it can be detected
+ below. */
+ xReceivedBytes = xReturned;
+ break;
+ }
+ else if( xReturned == 0 )
+ {
+ /* Timed out. */
+ break;
+ }
+ else
+ {
+ /* Keep a count of the bytes received so far. */
+ xReceivedBytes += xReturned;
+ }
+ }
+
+ /* If an error occurred it will be latched in xReceivedBytes,
+ otherwise xReceived bytes will be just that - the number of
+ bytes received from the echo server. */
+ if( xReceivedBytes > 0 )
+ {
+ /* Compare the transmitted string to the received string. */
+ configASSERT( strncmp( pcReceivedString, pcTransmittedString, lTransmitted ) == 0 );
+ if( strncmp( pcReceivedString, pcTransmittedString, lTransmitted ) == 0 )
+ {
+ /* The echo reply was received without error. */
+ ulTxRxCycles[ xInstance ]++;
+ }
+ else
+ {
+ /* The received string did not match the transmitted
+ string. */
+ ulTxRxFailures[ xInstance ]++;
+ break;
+ }
+ }
+ else if( xReceivedBytes < 0 )
+ {
+ /* FreeRTOS_recv() returned an error. */
+ break;
+ }
+ else
+ {
+ /* Timed out without receiving anything? */
+ break;
+ }
+ }
+
+ /* Finished using the connected socket, initiate a graceful close:
+ FIN, FIN+ACK, ACK. */
+ FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR );
+
+ /* Expect FreeRTOS_recv() to return an error once the shutdown is
+ complete. */
+ xTimeOnEntering = xTaskGetTickCount();
+ do
+ {
+ xReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */
+ &( pcReceivedString[ 0 ] ), /* The buffer into which the received data will be written. */
+ echoBUFFER_SIZES, /* The size of the buffer provided to receive the data. */
+ 0 );
+
+ if( xReturned < 0 )
+ {
+ break;
+ }
+
+ } while( ( xTaskGetTickCount() - xTimeOnEntering ) < xReceiveTimeOut );
+ }
+
+ /* Close this socket before looping back to create another. */
+ FreeRTOS_closesocket( xSocket );
+
+ /* Pause for a short while to ensure the network is not too
+ congested. */
+ vTaskDelay( echoLOOP_DELAY );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvCreateTxData( char *cBuffer, uint32_t ulBufferLength )
+{
+BaseType_t lCharactersToAdd, lCharacter;
+char cChar = '0';
+const BaseType_t lMinimumLength = 60;
+
+ /* Randomise the number of characters that will be sent in the echo
+ request. */
+ do
+ {
+ lCharactersToAdd = ipconfigRAND32() % ( ulBufferLength - 20UL );
+ } while ( ( lCharactersToAdd == 0 ) || ( lCharactersToAdd < lMinimumLength ) ); /* Must be at least enough to add the unique text to the start of the string later. */
+
+ /* Fill the buffer. */
+ for( lCharacter = 0; lCharacter < lCharactersToAdd; lCharacter++ )
+ {
+ cBuffer[ lCharacter ] = cChar;
+ cChar++;
+
+ if( cChar > '~' )
+ {
+ cChar = '0';
+ }
+ }
+
+ return lCharactersToAdd;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xAreSingleTaskTCPEchoClientsStillRunning( void )
+{
+static uint32_t ulLastEchoSocketCount[ echoNUM_ECHO_CLIENTS ] = { 0 }, ulLastConnections[ echoNUM_ECHO_CLIENTS ] = { 0 };
+BaseType_t xReturn = pdPASS, x;
+
+ /* Return fail is the number of cycles does not increment between
+ consecutive calls. */
+ for( x = 0; x < echoNUM_ECHO_CLIENTS; x++ )
+ {
+ if( ulTxRxCycles[ x ] == ulLastEchoSocketCount[ x ] )
+ {
+ xReturn = pdFAIL;
+ }
+ else
+ {
+ ulLastEchoSocketCount[ x ] = ulTxRxCycles[ x ];
+ }
+
+ if( ulConnections[ x ] == ulLastConnections[ x ] )
+ {
+ xReturn = pdFAIL;
+ }
+ else
+ {
+ ulConnections[ x ] = ulLastConnections[ x ];
+ }
+ }
+
+ return xReturn;
+}
+
+#endif /* ipconfigUSE_TCP */
+
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/include/SimpleUDPClientAndServer.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/include/SimpleUDPClientAndServer.h
new file mode 100644
index 000000000..daeec4993
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/include/SimpleUDPClientAndServer.h
@@ -0,0 +1,75 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+#ifndef SIMPLE_UDP_CLIENT_AND_SERVER_H
+#define SIMPLE_UDPCLIENT_AND_SERVER_H
+
+void vStartSimpleUDPClientServerTasks( uint16_t usStackSize, uint32_t ulsPort, UBaseType_t uxPriority );
+
+#endif /* SIMPLE_UDPCLIENT_AND_SERVER_H */
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/include/TCPEchoClient_SingleTasks.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/include/TCPEchoClient_SingleTasks.h
new file mode 100644
index 000000000..03dae2ff1
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/DemoTasks/include/TCPEchoClient_SingleTasks.h
@@ -0,0 +1,82 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+#ifndef SINGLE_TASK_TCP_ECHO_CLIENTS_H
+#define SINGLE_TASK_TCP_ECHO_CLIENTS_H
+
+/*
+ * Create the TCP echo client tasks. This is the version where an echo request
+ * is made from the same task that listens for the echo reply.
+ */
+void vStartTCPEchoClientTasks_SingleTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority );
+BaseType_t xAreSingleTaskTCPEchoClientsStillRunning( void );
+
+#endif /* SINGLE_TASK_TCP_ECHO_CLIENTS_H */
+
+
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOSConfig.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOSConfig.h
new file mode 100644
index 000000000..8f62f5a5e
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOSConfig.h
@@ -0,0 +1,261 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
+ * http://www.freertos.org/a00110.html
+ *
+ * The bottom of this file contains some constants specific to running the UDP
+ * stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than
+ * the demo) are contained in FreeRTOSIPConfig.h.
+ *----------------------------------------------------------*/
+#define configENABLE_BACKWARD_COMPATIBILITY 0
+#define configUSE_PREEMPTION 1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
+#define configMAX_PRIORITIES ( 7 )
+#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */
+#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */
+#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) )
+#define configMAX_TASK_NAME_LEN ( 15 )
+#define configUSE_TRACE_FACILITY 1
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_CO_ROUTINES 0
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configQUEUE_REGISTRY_SIZE 0
+#define configUSE_APPLICATION_TASK_TAG 0
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configUSE_ALTERNATIVE_API 0
+#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 3 /* FreeRTOS+FAT requires 2 pointers if a CWD is supported. */
+
+/* Hook function related definitions. */
+#define configUSE_TICK_HOOK 0
+#define configUSE_IDLE_HOOK 1
+#define configUSE_MALLOC_FAILED_HOOK 1
+#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */
+
+/* Software timer related definitions. */
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
+#define configTIMER_QUEUE_LENGTH 5
+#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 )
+
+/* Event group related definitions. */
+#define configUSE_EVENT_GROUPS 1
+
+/* Run time stats gathering definitions. */
+#define configGENERATE_RUN_TIME_STATS 0
+
+/* Co-routine definitions. */
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
+
+/* Set the following definitions to 1 to include the API function, or zero
+to exclude the API function. */
+#define INCLUDE_vTaskPrioritySet 1
+#define INCLUDE_uxTaskPriorityGet 1
+#define INCLUDE_vTaskDelete 1
+#define INCLUDE_vTaskCleanUpResources 0
+#define INCLUDE_vTaskSuspend 1
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 1
+#define INCLUDE_xTaskGetSchedulerState 1
+#define INCLUDE_xTimerGetTimerTaskHandle 0
+#define INCLUDE_xTaskGetIdleTaskHandle 0
+#define INCLUDE_xQueueGetMutexHolder 1
+#define INCLUDE_eTaskGetState 1
+#define INCLUDE_xEventGroupSetBitsFromISR 1
+#define INCLUDE_xTimerPendFunctionCall 1
+#define INCLUDE_pcTaskGetTaskName 1
+
+/* This demo makes use of one or more example stats formatting functions. These
+format the raw data provided by the uxTaskGetSystemState() function in to human
+readable ASCII form. See the notes in the implementation of vTaskList() within
+FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS
+is set to 2 so the formatting functions are included without the stdio.h being
+included in tasks.c. That is because this project defines its own sprintf()
+functions. */
+#define configUSE_STATS_FORMATTING_FUNCTIONS 1
+
+/* Assert call defined for debug builds. */
+#ifdef _DEBUG
+ extern void vAssertCalled( const char *pcFile, uint32_t ulLine );
+ #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ )
+#endif /* _DEBUG */
+
+
+
+/* Application specific definitions follow. **********************************/
+
+/* If configINCLUDE_DEMO_DEBUG_STATS is set to one, then a few basic IP trace
+macros are defined to gather some UDP stack statistics that can then be viewed
+through the CLI interface. */
+#define configINCLUDE_DEMO_DEBUG_STATS 1
+
+/* The size of the global output buffer that is available for use when there
+are multiple command interpreters running at once (for example, one on a UART
+and one on TCP/IP). This is done to prevent an output buffer being defined by
+each implementation - which would waste RAM. In this case, there is only one
+command interpreter running, and it has its own local output buffer, so the
+global buffer is just set to be one byte long as it is not used and should not
+take up unnecessary RAM. */
+#define configCOMMAND_INT_MAX_OUTPUT_SIZE 1
+
+/* Only used when running in the FreeRTOS Windows simulator. Defines the
+priority of the task used to simulate Ethernet interrupts. */
+#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 )
+
+/* This demo creates a virtual network connection by accessing the raw Ethernet
+or WiFi data to and from a real network connection. Many computers have more
+than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell
+the demo which real port should be used to create the virtual port. The ports
+available are displayed on the console when the application is executed. For
+example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4
+results in the wired network being used, while setting
+configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being
+used. */
+#define configNETWORK_INTERFACE_TO_USE 4L
+
+/* The address of an echo server that will be used by the two demo echo client
+tasks.
+http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients.html
+http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_Echo_Clients.html */
+#define configECHO_SERVER_ADDR0 192
+#define configECHO_SERVER_ADDR1 168
+#define configECHO_SERVER_ADDR2 0
+#define configECHO_SERVER_ADDR3 11
+
+/* Default MAC address configuration. The demo creates a virtual network
+connection that uses this MAC address by accessing the raw Ethernet/WiFi data
+to and from a real network connection on the host PC. See the
+configNETWORK_INTERFACE_TO_USE definition above for information on how to
+configure the real network connection to use. */
+#define configMAC_ADDR0 0x00
+#define configMAC_ADDR1 0x11
+#define configMAC_ADDR2 0x22
+#define configMAC_ADDR3 0x33
+#define configMAC_ADDR4 0x44
+#define configMAC_ADDR5 0x41
+
+/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or
+ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */
+#define configIP_ADDR0 172
+#define configIP_ADDR1 25
+#define configIP_ADDR2 218
+#define configIP_ADDR3 200
+
+/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to
+0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */
+#define configGATEWAY_ADDR0 172
+#define configGATEWAY_ADDR1 25
+#define configGATEWAY_ADDR2 218
+#define configGATEWAY_ADDR3 1
+
+/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and
+208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set
+to 1 but a DNS server cannot be contacted.*/
+#define configDNS_SERVER_ADDR0 208
+#define configDNS_SERVER_ADDR1 67
+#define configDNS_SERVER_ADDR2 222
+#define configDNS_SERVER_ADDR3 222
+
+/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or
+ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */
+#define configNET_MASK0 255
+#define configNET_MASK1 255
+#define configNET_MASK2 0
+#define configNET_MASK3 0
+
+/* The UDP port to which print messages are sent. */
+#define configPRINT_PORT ( 15000 )
+
+#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) )
+ /* Map to Windows names. */
+ #define snprintf _snprintf
+ #define vsnprintf _vsnprintf
+#endif
+
+/* Visual studio does not have an implementation of strcasecmp(). */
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+#define strcmpi _strcmpi
+
+#endif /* FREERTOS_CONFIG_H */
+
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOSIPConfig.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOSIPConfig.h
new file mode 100644
index 000000000..9be333e45
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOSIPConfig.h
@@ -0,0 +1,349 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+
+/*****************************************************************************
+ *
+ * See the following URL for configuration information.
+ * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html
+ *
+ *****************************************************************************/
+
+#ifndef FREERTOS_IP_CONFIG_H
+#define FREERTOS_IP_CONFIG_H
+
+/* Prototype for the function used to print out. In this case it prints to the
+console before the network is connected then a UDP port after the network has
+connected. */
+extern void vLoggingPrintf( const char *pcFormatString, ... );
+
+/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to
+1 then FreeRTOS_debug_printf should be defined to the function used to print
+out the debugging messages. */
+#define ipconfigHAS_DEBUG_PRINTF 0
+#if( ipconfigHAS_DEBUG_PRINTF == 1 )
+ #define FreeRTOS_debug_printf(X) vLoggingPrintf X
+#endif
+
+/* Set to 1 to print out non debugging messages, for example the output of the
+FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1
+then FreeRTOS_printf should be set to the function used to print out the
+messages. */
+#define ipconfigHAS_PRINTF 1
+#if( ipconfigHAS_PRINTF == 1 )
+ #define FreeRTOS_printf(X) vLoggingPrintf X
+#endif
+
+/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing
+on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */
+#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN
+
+/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums)
+then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software
+stack repeating the checksum calculations. */
+#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1
+
+/* Several API's will block until the result is known, or the action has been
+performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be
+set per socket, using setsockopt(). If not set, the times below will be
+used as defaults. */
+#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 )
+#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 )
+
+/* Include support for LLMNR: Link-local Multicast Name Resolution
+(non-Microsoft) */
+#define ipconfigUSE_LLMNR ( 1 )
+
+/* Include support for NBNS: NetBIOS Name Service (Microsoft) */
+#define ipconfigUSE_NBNS ( 1 )
+
+/* Include support for DNS caching. For TCP, having a small DNS cache is very
+useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low
+and also DNS may use small timeouts. If a DNS reply comes in after the DNS
+socket has been destroyed, the result will be stored into the cache. The next
+call to FreeRTOS_gethostbyname() will return immediately, without even creating
+a socket. */
+#define ipconfigUSE_DNS_CACHE ( 1 )
+#define ipconfigDNS_CACHE_NAME_LENGTH ( 16 )
+#define ipconfigDNS_CACHE_ENTRIES ( 4 )
+#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 )
+
+/* The IP stack executes it its own task (although any application task can make
+use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY
+sets the priority of the task that executes the IP stack. The priority is a
+standard FreeRTOS task priority so can take any value from 0 (the lowest
+priority) to (configMAX_PRIORITIES - 1) (the highest priority).
+configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in
+FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to
+the priority assigned to the task executing the IP stack relative to the
+priority assigned to tasks that use the IP stack. */
+#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 )
+
+/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP
+task. This setting is less important when the FreeRTOS Win32 simulator is used
+as the Win32 simulator only stores a fixed amount of information on the task
+stack. FreeRTOS includes optional stack overflow detection, see:
+http://www.freertos.org/Stacks-and-stack-overflow-checking.html */
+#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 )
+
+/* ipconfigRAND32() is called by the IP stack to generate random numbers for
+things such as a DHCP transaction number or initial sequence number. Random
+number generation is performed via this macro to allow applications to use their
+own random number generation method. For example, it might be possible to
+generate a random number by sampling noise on an analogue input. */
+extern UBaseType_t uxRand();
+#define ipconfigRAND32() uxRand()
+
+/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the
+network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK
+is not set to 1 then the network event hook will never be called. See
+http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml
+*/
+#define ipconfigUSE_NETWORK_EVENT_HOOK 1
+
+/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but
+a network buffer cannot be obtained then the calling task is held in the Blocked
+state (so other tasks can continue to executed) until either a network buffer
+becomes available or the send block time expires. If the send block time expires
+then the send operation is aborted. The maximum allowable send block time is
+capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the
+maximum allowable send block time prevents prevents a deadlock occurring when
+all the network buffers are in use and the tasks that process (and subsequently
+free) the network buffers are themselves blocked waiting for a network buffer.
+ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in
+milliseconds can be converted to a time in ticks by dividing the time in
+milliseconds by portTICK_PERIOD_MS. */
+#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS )
+
+/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP
+address, netmask, DNS server address and gateway address from a DHCP server. If
+ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The
+stack will revert to using the static IP address even when ipconfigUSE_DHCP is
+set to 1 if a valid configuration cannot be obtained from a DHCP server for any
+reason. The static configuration used is that passed into the stack by the
+FreeRTOS_IPInit() function call. */
+#define ipconfigUSE_DHCP 1
+
+/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at
+increasing time intervals until either a reply is received from a DHCP server
+and accepted, or the interval between transmissions reaches
+ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the
+static IP address passed as a parameter to FreeRTOS_IPInit() if the
+re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without
+a DHCP reply being received. */
+#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS )
+
+/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP
+stack can only send a UDP message to a remove IP address if it knowns the MAC
+address associated with the IP address, or the MAC address of the router used to
+contact the remote IP address. When a UDP message is received from a remote IP
+address the MAC address and IP address are added to the ARP cache. When a UDP
+message is sent to a remote IP address that does not already appear in the ARP
+cache then the UDP message is replaced by a ARP message that solicits the
+required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum
+number of entries that can exist in the ARP table at any one time. */
+#define ipconfigARP_CACHE_ENTRIES 6
+
+/* ARP requests that do not result in an ARP response will be re-transmitted a
+maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is
+aborted. */
+#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 )
+
+/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP
+table being created or refreshed and the entry being removed because it is stale.
+New ARP requests are sent for ARP cache entries that are nearing their maximum
+age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is
+equal to 1500 seconds (or 25 minutes). */
+#define ipconfigMAX_ARP_AGE 150
+
+/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling
+routines, which are relatively large. To save code space the full
+FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster
+alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr()
+takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter.
+FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets
+(for example, 192, 168, 0, 1) as its parameters. If
+ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and
+FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is
+not set to 1 then only FreeRTOS_indet_addr_quick() is available. */
+#define ipconfigINCLUDE_FULL_INET_ADDR 1
+
+/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that
+are available to the IP stack. The total number of network buffers is limited
+to ensure the total amount of RAM that can be consumed by the IP stack is capped
+to a pre-determinable value. */
+#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60
+
+/* A FreeRTOS queue is used to send events from application tasks to the IP
+stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can
+be queued for processing at any one time. The event queue must be a minimum of
+5 greater than the total number of network buffers. */
+#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 )
+
+/* The address of a socket is the combination of its IP address and its port
+number. FreeRTOS_bind() is used to manually allocate a port number to a socket
+(to 'bind' the socket to a port), but manual binding is not normally necessary
+for client sockets (those sockets that initiate outgoing connections rather than
+wait for incoming connections on a known port number). If
+ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling
+FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP
+stack automatically binding the socket to a port number from the range
+socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If
+ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto()
+on a socket that has not yet been bound will result in the send operation being
+aborted. */
+#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1
+
+/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */
+#define ipconfigUDP_TIME_TO_LIVE 128
+#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */
+
+/* USE_TCP: Use TCP and all its features */
+#define ipconfigUSE_TCP ( 1 )
+
+/* USE_WIN: Let TCP use windowing mechanism. */
+#define ipconfigUSE_TCP_WIN ( 1 )
+
+/* The MTU is the maximum number of bytes the payload of a network frame can
+contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a
+lower value can save RAM, depending on the buffer management scheme used. If
+ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must
+be divisible by 8. */
+#define ipconfigNETWORK_MTU 1200
+
+/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used
+through the FreeRTOS_gethostbyname() API function. */
+#define ipconfigUSE_DNS 1
+
+/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will
+generate replies to incoming ICMP echo (ping) requests. */
+#define ipconfigREPLY_TO_INCOMING_PINGS 1
+
+/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the
+FreeRTOS_SendPingRequest() API function is available. */
+#define ipconfigSUPPORT_OUTGOING_PINGS 0
+
+/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select()
+(and associated) API function is available. */
+#define ipconfigSUPPORT_SELECT_FUNCTION 1
+
+/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames
+that are not in Ethernet II format will be dropped. This option is included for
+potential future IP stack developments. */
+#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1
+
+/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the
+responsibility of the Ethernet interface to filter out packets that are of no
+interest. If the Ethernet interface does not implement this functionality, then
+set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack
+perform the filtering instead (it is much less efficient for the stack to do it
+because the packet will already have been passed into the stack). If the
+Ethernet driver does all the necessary filtering in hardware then software
+filtering can be removed by using a value other than 1 or 0. */
+#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1
+
+/* The windows simulator cannot really simulate MAC interrupts, and needs to
+block occasionally to allow other tasks to run. */
+#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS )
+
+/* Advanced only: in order to access 32-bit fields in the IP packets with
+32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits.
+This has to do with the contents of the IP-packets: all 32-bit fields are
+32-bit-aligned, plus 16-bit(!) */
+#define ipconfigPACKET_FILLER_SIZE 2
+
+/* Define the size of the pool of TCP window descriptors. On the average, each
+TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6
+outstanding packets (for Rx and Tx). When using up to 10 TP sockets
+simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */
+#define ipconfigTCP_WIN_SEG_COUNT 240
+
+/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed
+maximum size. Define the size of Rx buffer for TCP sockets. */
+#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 )
+
+/* Define the size of Tx buffer for TCP sockets. */
+#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 )
+
+/* When using call-back handlers, the driver may check if the handler points to
+real program memory (RAM or flash) or just has a random non-zero value. */
+#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL )
+
+/* Include support for TCP hang protection. All sockets in a connecting or
+disconnecting stage will timeout after a period of non-activity. */
+#define ipconfigTCP_HANG_PROTECTION ( 1 )
+#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 )
+
+/* Include support for TCP keep-alive messages. */
+#define ipconfigTCP_KEEP_ALIVE ( 1 )
+#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */
+
+#define portINLINE __inline
+
+#endif /* FREERTOS_IP_CONFIG_H */
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOS_Plus_TCP_Minimal.sln b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOS_Plus_TCP_Minimal.sln
new file mode 100644
index 000000000..b362f36c5
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOS_Plus_TCP_Minimal.sln
@@ -0,0 +1,23 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}"
+EndProject
+Global
+ GlobalSection(TestCaseManagementSettings) = postSolution
+ CategoryFile = FreeRTOS_Plus_TCP_Minimal.vsmdi
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32
+ {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.ActiveCfg = Release|Win32
+ {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOS_Plus_TCP_Minimal.suo b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOS_Plus_TCP_Minimal.suo
new file mode 100644
index 000000000..6a1e0ebff
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/FreeRTOS_Plus_TCP_Minimal.suo
Binary files differ
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/ReadMe.txt b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/ReadMe.txt
new file mode 100644
index 000000000..682a18c8d
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/ReadMe.txt
@@ -0,0 +1,34 @@
+The FreeRTOS+TCP source code and example projects are currently provided in
+their own .zip file download, but using the directory structure of the official
+FreeRTOS .zip file download. This allow the projects to be seamlessly moved
+from one download to the other, but can seem strange when the files are viewed
+in isolation.
+
+The minimal FreeRTOS+TCP Visual Studio project file is in the following directory:
+FreeRTOS-Plus\Demo\FreeRTOS_Plus_TCP_Minimal_Windows_Simulator
+
+The minimal project is a cut down version of the full Windows demo that only
+includes examples of simple TCP and UDP clients. The instructions for the full
+Windows demo are still relevant though as they describe how to set up the
+WinPCap development environment, how to set the IP address, and other such
+items. Note that, as delivered, configUSE_DHCP is set to 0, so a static IP
+address is used. The instructions are provided on the following URL:
+http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html
+
+The UDP client example included in the minimal project is described on the
+following URL:
+http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_client_server.html
+
+The TCP client example included in the minimal project is described on the
+following URL:
+http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients.html
+
+A description of the FreeRTOS+TCP source code directory is provided on the
+following URL:
+http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Networking_Tutorial_Source_Code_Organisation.html
+
+A description of the way the main FreeRTOS .zip file download source code is
+organised is provided on the following URL:
+http://www.freertos.org/a00017.html
+
+
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/Read_Me_Build_Instructions.url b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/Read_Me_Build_Instructions.url
new file mode 100644
index 000000000..3ceab7642
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/Read_Me_Build_Instructions.url
@@ -0,0 +1,6 @@
+[{000214A0-0000-0000-C000-000000000046}]
+Prop3=19,2
+[InternetShortcut]
+URL=http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html
+IDList=
+HotKey=0
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WIN32.vcxproj b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WIN32.vcxproj
new file mode 100644
index 000000000..14a8d8aa9
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WIN32.vcxproj
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{C686325E-3261-42F7-AEB1-DDE5280E1CEB}</ProjectGuid>
+ <ProjectName>RTOSDemo</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <TypeLibraryName>.\Debug/WIN32.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\Source\FreeRTOS-Plus-FAT\include;..\..\Source\FreeRTOS-Plus-FAT\portable\common;..\..\Source\FreeRTOS-Plus-TCP\protocols\include;..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;.\DemoTasks\include;..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\WinPCap;..\..\..\FreeRTOS\Source\include;..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\Source\FreeRTOS-Plus-CLI;.\TraceMacros\Example1;..\..\Source\FreeRTOS-Plus-TCP\include;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <PrecompiledHeaderOutputFile>.\Debug/WIN32.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
+ <ObjectFileName>.\Debug/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
+ <WarningLevel>Level4</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DisableLanguageExtensions>false</DisableLanguageExtensions>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <AdditionalOptions>/wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 %(AdditionalOptions)</AdditionalOptions>
+ <BrowseInformation>true</BrowseInformation>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <ExceptionHandling>false</ExceptionHandling>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0c09</Culture>
+ </ResourceCompile>
+ <Link>
+ <OutputFile>.\Debug/RTOSDemo.exe</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>.\Debug/WIN32.pdb</ProgramDatabaseFile>
+ <SubSystem>Console</SubSystem>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalDependencies>wpcap.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>.\WinPCap</AdditionalLibraryDirectories>
+ <Profile>false</Profile>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Debug/WIN32.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <TypeLibraryName>.\Release/WIN32.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <PreprocessorDefinitions>_WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeaderOutputFile>.\Release/WIN32.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Release/</AssemblerListingLocation>
+ <ObjectFileName>.\Release/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalIncludeDirectories>..\Common\Utils;..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap;..\Common\ethernet\lwip-1.4.0\src\include\ipv4;..\Common\ethernet\lwip-1.4.0\src\include;..\..\Source\include;..\..\Source\portable\MSVC-MingW;..\Common\ethernet\lwip-1.4.0\ports\win32\include;..\Common\Include;.\lwIP_Apps;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0c09</Culture>
+ </ResourceCompile>
+ <Link>
+ <OutputFile>.\Release/RTOSDemo.exe</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <ProgramDatabaseFile>.\Release/WIN32.pdb</ProgramDatabaseFile>
+ <SubSystem>Console</SubSystem>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap</AdditionalLibraryDirectories>
+ <AdditionalDependencies>wpcap.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Release/WIN32.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\..\FreeRTOS\Source\event_groups.c" />
+ <ClCompile Include="..\..\..\FreeRTOS\Source\list.c" />
+ <ClCompile Include="..\..\..\FreeRTOS\Source\portable\MemMang\heap_4.c" />
+ <ClCompile Include="..\..\..\FreeRTOS\Source\portable\MSVC-MingW\port.c" />
+ <ClCompile Include="..\..\..\FreeRTOS\Source\queue.c" />
+ <ClCompile Include="..\..\..\FreeRTOS\Source\tasks.c" />
+ <ClCompile Include="..\..\..\FreeRTOS\Source\timers.c" />
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_ARP.c" />
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_DHCP.c" />
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_DNS.c" />
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_IP.c" />
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_Sockets.c" />
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_Stream_Buffer.c" />
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_TCP_IP.c" />
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_TCP_WIN.c" />
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_UDP_IP.c" />
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement\BufferAllocation_2.c" />
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\portable\NetworkInterface\WinPCap\NetworkInterface.c" />
+ <ClCompile Include="DemoTasks\TCPEchoClient_SingleTasks.c" />
+ <ClCompile Include="DemoTasks\SimpleUDPClientAndServer.c" />
+ <ClCompile Include="demo_logging.c" />
+ <ClCompile Include="main.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\event_groups.h" />
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\FreeRTOS.h" />
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\portable.h" />
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\projdefs.h" />
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\queue.h" />
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\semphr.h" />
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\task.h" />
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\timers.h" />
+ <ClInclude Include="..\..\..\FreeRTOS\Source\portable\MSVC-MingW\portmacro.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOSIPConfigDefaults.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_ARP.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_DHCP.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_DNS.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_IP.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_IP_Private.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_Sockets.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_Stream_Buffer.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_TCP_IP.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_TCP_WIN.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_UDP_IP.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\IPTraceMacroDefaults.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\NetworkBufferManagement.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\NetworkInterface.h" />
+ <ClInclude Include="FreeRTOSConfig.h" />
+ <ClInclude Include="FreeRTOSIPConfig.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WIN32.vcxproj.filters
new file mode 100644
index 000000000..48849714c
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WIN32.vcxproj.filters
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{38712199-cebf-4124-bf15-398f7c3419ea}</UniqueIdentifier>
+ <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
+ </Filter>
+ <Filter Include="FreeRTOS">
+ <UniqueIdentifier>{af3445a1-4908-4170-89ed-39345d90d30c}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="FreeRTOS\Source">
+ <UniqueIdentifier>{f32be356-4763-4cae-9020-974a2638cb08}</UniqueIdentifier>
+ <Extensions>*.c</Extensions>
+ </Filter>
+ <Filter Include="FreeRTOS\Source\Portable">
+ <UniqueIdentifier>{88f409e6-d396-4ac5-94bd-7a99c914be46}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="FreeRTOS+">
+ <UniqueIdentifier>{e5ad4ec7-23dc-4295-8add-2acaee488f5a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="FreeRTOS\Source\include">
+ <UniqueIdentifier>{d2dcd641-8d91-492b-852f-5563ffadaec6}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="FreeRTOS+\FreeRTOS+TCP">
+ <UniqueIdentifier>{8672fa26-b119-481f-8b8d-086419c01a3e}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="FreeRTOS+\FreeRTOS+TCP\portable">
+ <UniqueIdentifier>{4570be11-ec96-4b55-ac58-24b50ada980a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="FreeRTOS+\FreeRTOS+TCP\include">
+ <UniqueIdentifier>{5d93ed51-023a-41ad-9243-8d230165d34b}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="DemoTasks">
+ <UniqueIdentifier>{b71e974a-9f28-4815-972b-d930ba8a34d0}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\..\FreeRTOS\Source\portable\MSVC-MingW\port.c">
+ <Filter>FreeRTOS\Source\Portable</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\FreeRTOS\Source\timers.c">
+ <Filter>FreeRTOS\Source</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\FreeRTOS\Source\list.c">
+ <Filter>FreeRTOS\Source</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\FreeRTOS\Source\queue.c">
+ <Filter>FreeRTOS\Source</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\FreeRTOS\Source\tasks.c">
+ <Filter>FreeRTOS\Source</Filter>
+ </ClCompile>
+ <ClCompile Include="DemoTasks\SimpleUDPClientAndServer.c">
+ <Filter>DemoTasks</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_UDP_IP.c">
+ <Filter>FreeRTOS+\FreeRTOS+TCP</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_DHCP.c">
+ <Filter>FreeRTOS+\FreeRTOS+TCP</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_DNS.c">
+ <Filter>FreeRTOS+\FreeRTOS+TCP</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_Sockets.c">
+ <Filter>FreeRTOS+\FreeRTOS+TCP</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement\BufferAllocation_2.c">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\portable</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\portable\NetworkInterface\WinPCap\NetworkInterface.c">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\portable</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_ARP.c">
+ <Filter>FreeRTOS+\FreeRTOS+TCP</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_IP.c">
+ <Filter>FreeRTOS+\FreeRTOS+TCP</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_TCP_IP.c">
+ <Filter>FreeRTOS+\FreeRTOS+TCP</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_TCP_WIN.c">
+ <Filter>FreeRTOS+\FreeRTOS+TCP</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\FreeRTOS\Source\event_groups.c">
+ <Filter>FreeRTOS\Source</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\FreeRTOS\Source\portable\MemMang\heap_4.c">
+ <Filter>FreeRTOS\Source\Portable</Filter>
+ </ClCompile>
+ <ClCompile Include="main.c" />
+ <ClCompile Include="DemoTasks\TCPEchoClient_SingleTasks.c">
+ <Filter>DemoTasks</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Source\FreeRTOS-Plus-TCP\FreeRTOS_Stream_Buffer.c">
+ <Filter>FreeRTOS+\FreeRTOS+TCP</Filter>
+ </ClCompile>
+ <ClCompile Include="demo_logging.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\NetworkInterface.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_DNS.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_Sockets.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_UDP_IP.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\timers.h">
+ <Filter>FreeRTOS\Source\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\event_groups.h">
+ <Filter>FreeRTOS\Source\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\FreeRTOS.h">
+ <Filter>FreeRTOS\Source\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\queue.h">
+ <Filter>FreeRTOS\Source\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\semphr.h">
+ <Filter>FreeRTOS\Source\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\task.h">
+ <Filter>FreeRTOS\Source\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\FreeRTOS\Source\portable\MSVC-MingW\portmacro.h">
+ <Filter>FreeRTOS\Source\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_IP_Private.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\NetworkBufferManagement.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_ARP.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_DHCP.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_IP.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_TCP_IP.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_TCP_WIN.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOSIPConfigDefaults.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\IPTraceMacroDefaults.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="FreeRTOSConfig.h" />
+ <ClInclude Include="FreeRTOSIPConfig.h" />
+ <ClInclude Include="..\..\Source\FreeRTOS-Plus-TCP\include\FreeRTOS_Stream_Buffer.h">
+ <Filter>FreeRTOS+\FreeRTOS+TCP\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\portable.h">
+ <Filter>FreeRTOS\Source\include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\FreeRTOS\Source\include\projdefs.h">
+ <Filter>FreeRTOS\Source\include</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/Packet32.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/Packet32.h
new file mode 100644
index 000000000..1e0eacd77
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/Packet32.h
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino, CACE Technologies
+ * nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/** @ingroup packetapi
+ * @{
+ */
+
+/** @defgroup packet32h Packet.dll definitions and data structures
+ * Packet32.h contains the data structures and the definitions used by packet.dll.
+ * The file is used both by the Win9x and the WinNTx versions of packet.dll, and can be included
+ * by the applications that use the functions of this library
+ * @{
+ */
+
+#ifndef __PACKET32
+#define __PACKET32
+
+#include <winsock2.h>
+
+#ifdef HAVE_AIRPCAP_API
+#include <airpcap.h>
+#else
+#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_)
+#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_
+typedef struct _AirpcapHandle *PAirpcapHandle;
+#endif /* AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ */
+#endif /* HAVE_AIRPCAP_API */
+
+#ifdef HAVE_DAG_API
+#include <dagc.h>
+#endif /* HAVE_DAG_API */
+
+// Working modes
+#define PACKET_MODE_CAPT 0x0 ///< Capture mode
+#define PACKET_MODE_STAT 0x1 ///< Statistical mode
+#define PACKET_MODE_MON 0x2 ///< Monitoring mode
+#define PACKET_MODE_DUMP 0x10 ///< Dump mode
+#define PACKET_MODE_STAT_DUMP MODE_DUMP | MODE_STAT ///< Statistical dump Mode
+
+
+/// Alignment macro. Defines the alignment size.
+#define Packet_ALIGNMENT sizeof(int)
+/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT.
+#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1))
+
+#define NdisMediumNull -1 ///< Custom linktype: NDIS doesn't provide an equivalent
+#define NdisMediumCHDLC -2 ///< Custom linktype: NDIS doesn't provide an equivalent
+#define NdisMediumPPPSerial -3 ///< Custom linktype: NDIS doesn't provide an equivalent
+#define NdisMediumBare80211 -4 ///< Custom linktype: NDIS doesn't provide an equivalent
+#define NdisMediumRadio80211 -5 ///< Custom linktype: NDIS doesn't provide an equivalent
+#define NdisMediumPpi -6 ///< Custom linktype: NDIS doesn't provide an equivalent
+
+// Loopback behaviour definitions
+#define NPF_DISABLE_LOOPBACK 1 ///< Drop the packets sent by the NPF driver
+#define NPF_ENABLE_LOOPBACK 2 ///< Capture the packets sent by the NPF driver
+
+/*!
+ \brief Network type structure.
+
+ This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed.
+*/
+typedef struct NetType
+{
+ UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information)
+ ULONGLONG LinkSpeed; ///< The speed of the network in bits per second
+}NetType;
+
+
+//some definitions stolen from libpcap
+
+#ifndef BPF_MAJOR_VERSION
+
+/*!
+ \brief A BPF pseudo-assembly program.
+
+ The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet.
+*/
+struct bpf_program
+{
+ UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow.
+ struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program.
+};
+
+/*!
+ \brief A single BPF pseudo-instruction.
+
+ bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver.
+*/
+struct bpf_insn
+{
+ USHORT code; ///< Instruction type and addressing mode.
+ UCHAR jt; ///< Jump if true
+ UCHAR jf; ///< Jump if false
+ int k; ///< Generic field used for various purposes.
+};
+
+/*!
+ \brief Structure that contains a couple of statistics values on the current capture.
+
+ It is used by packet.dll to return statistics about a capture session.
+*/
+struct bpf_stat
+{
+ UINT bs_recv; ///< Number of packets that the driver received from the network adapter
+ ///< from the beginning of the current capture. This value includes the packets
+ ///< lost by the driver.
+ UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture.
+ ///< Basically, a packet is lost when the the buffer of the driver is full.
+ ///< In this situation the packet cannot be stored and the driver rejects it.
+ UINT ps_ifdrop; ///< drops by interface. XXX not yet supported
+ UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and
+ ///< thus reach the application.
+};
+
+/*!
+ \brief Packet header.
+
+ This structure defines the header associated with every packet delivered to the application.
+*/
+struct bpf_hdr
+{
+ struct timeval bh_tstamp; ///< The timestamp associated with the captured packet.
+ ///< It is stored in a TimeVal structure.
+ UINT bh_caplen; ///< Length of captured portion. The captured portion <b>can be different</b>
+ ///< from the original packet, because it is possible (with a proper filter)
+ ///< to instruct the driver to capture only a portion of the packets.
+ UINT bh_datalen; ///< Original length of packet
+ USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases,
+ ///< a padding could be added between the end of this structure and the packet
+ ///< data for performance reasons. This filed can be used to retrieve the actual data
+ ///< of the packet.
+};
+
+/*!
+ \brief Dump packet header.
+
+ This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets().
+ It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a
+ packet in a dump file. This makes straightforward sending WinPcap dump files to the network.
+*/
+struct dump_bpf_hdr{
+ struct timeval ts; ///< Time stamp of the packet
+ UINT caplen; ///< Length of captured portion. The captured portion can smaller than the
+ ///< the original packet, because it is possible (with a proper filter) to
+ ///< instruct the driver to capture only a portion of the packets.
+ UINT len; ///< Length of the original packet (off wire).
+};
+
+
+#endif
+
+struct bpf_stat;
+
+#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices
+#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links
+#define NMAX_PACKET 65535
+
+/*!
+ \brief Addresses of a network adapter.
+
+ This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with
+ an adapter.
+*/
+typedef struct npf_if_addr {
+ struct sockaddr_storage IPAddress; ///< IP address.
+ struct sockaddr_storage SubnetMask; ///< Netmask for that address.
+ struct sockaddr_storage Broadcast; ///< Broadcast address.
+}npf_if_addr;
+
+
+#define ADAPTER_NAME_LENGTH 256 + 12 ///< Maximum length for the name of an adapter. The value is the same used by the IP Helper API.
+#define ADAPTER_DESC_LENGTH 128 ///< Maximum length for the description of an adapter. The value is the same used by the IP Helper API.
+#define MAX_MAC_ADDR_LENGTH 8 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API.
+#define MAX_NETWORK_ADDRESSES 16 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API.
+
+
+typedef struct WAN_ADAPTER_INT WAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API
+typedef WAN_ADAPTER *PWAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API
+
+#define INFO_FLAG_NDIS_ADAPTER 0 ///< Flag for ADAPTER_INFO: this is a traditional ndis adapter
+#define INFO_FLAG_NDISWAN_ADAPTER 1 ///< Flag for ADAPTER_INFO: this is a NdisWan adapter, and it's managed by WANPACKET
+#define INFO_FLAG_DAG_CARD 2 ///< Flag for ADAPTER_INFO: this is a DAG card
+#define INFO_FLAG_DAG_FILE 6 ///< Flag for ADAPTER_INFO: this is a DAG file
+#define INFO_FLAG_DONT_EXPORT 8 ///< Flag for ADAPTER_INFO: when this flag is set, the adapter will not be listed or openend by winpcap. This allows to prevent exporting broken network adapters, like for example FireWire ones.
+#define INFO_FLAG_AIRPCAP_CARD 16 ///< Flag for ADAPTER_INFO: this is an airpcap card
+#define INFO_FLAG_NPFIM_DEVICE 32
+
+/*!
+ \brief Describes an opened network adapter.
+
+ This structure is the most important for the functioning of packet.dll, but the great part of its fields
+ should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters
+*/
+typedef struct _ADAPTER {
+ HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver.
+ CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened.
+ int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated
+ ///< on the wire.
+ HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter.
+ ///< It can be passed to standard Win32 functions (like WaitForSingleObject
+ ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some
+ ///< data. It is particularly useful in GUI applications that need to wait
+ ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy()
+ ///< function can be used to define the minimum amount of data in the kernel buffer
+ ///< that will cause the event to be signalled.
+
+ UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and
+ ///< ReadEvent will be signaled, also if no packets were captured
+ CHAR Name[ADAPTER_NAME_LENGTH];
+ PWAN_ADAPTER pWanAdapter;
+ UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API.
+
+#ifdef HAVE_AIRPCAP_API
+ PAirpcapHandle AirpcapAd;
+#endif // HAVE_AIRPCAP_API
+
+#ifdef HAVE_NPFIM_API
+ void* NpfImHandle;
+#endif // HAVE_NPFIM_API
+
+#ifdef HAVE_DAG_API
+ dagc_t *pDagCard; ///< Pointer to the dagc API adapter descriptor for this adapter
+ PCHAR DagBuffer; ///< Pointer to the buffer with the packets that is received from the DAG card
+ struct timeval DagReadTimeout; ///< Read timeout. The dagc API requires a timeval structure
+ unsigned DagFcsLen; ///< Length of the frame check sequence attached to any packet by the card. Obtained from the registry
+ DWORD DagFastProcess; ///< True if the user requests fast capture processing on this card. Higher level applications can use this value to provide a faster but possibly unprecise capture (for example, libpcap doesn't convert the timestamps).
+#endif // HAVE_DAG_API
+} ADAPTER, *LPADAPTER;
+
+/*!
+ \brief Structure that contains a group of packets coming from the driver.
+
+ This structure defines the header associated with every packet delivered to the application.
+*/
+typedef struct _PACKET {
+ HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications.
+ OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications.
+ PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for
+ ///< details about the organization of the data in this buffer
+ UINT Length; ///< Length of the buffer
+ DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data
+ ///< received by the last call to PacketReceivePacket()
+ BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications.
+} PACKET, *LPPACKET;
+
+/*!
+ \brief Structure containing an OID request.
+
+ It is used by the PacketRequest() function to send an OID to the interface card driver.
+ It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address,
+ the list of the multicast groups defined on it, and so on.
+*/
+struct _PACKET_OID_DATA {
+ ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h
+ ///< for a complete list of valid codes.
+ ULONG Length; ///< Length of the data field
+ UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received
+ ///< from the adapter.
+};
+typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @}
+ */
+
+/*
+BOOLEAN QueryWinPcapRegistryStringA(CHAR *SubKeyName,
+ CHAR *Value,
+ UINT *pValueLen,
+ CHAR *DefaultVal);
+
+BOOLEAN QueryWinPcapRegistryStringW(WCHAR *SubKeyName,
+ WCHAR *Value,
+ UINT *pValueLen,
+ WCHAR *DefaultVal);
+*/
+
+//---------------------------------------------------------------------------
+// EXPORTED FUNCTIONS
+//---------------------------------------------------------------------------
+
+PCHAR PacketGetVersion();
+PCHAR PacketGetDriverVersion();
+BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes);
+BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites);
+BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode);
+BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout);
+BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp);
+BOOLEAN PacketSetLoopbackBehavior(LPADAPTER AdapterObject, UINT LoopbackBehavior);
+INT PacketSetSnapLen(LPADAPTER AdapterObject,int snaplen);
+BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s);
+BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s);
+BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim);
+BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type);
+LPADAPTER PacketOpenAdapter(PCHAR AdapterName);
+BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync);
+INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync);
+LPPACKET PacketAllocatePacket(void);
+VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length);
+VOID PacketFreePacket(LPPACKET lpPacket);
+BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync);
+BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter);
+BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize);
+BOOLEAN PacketGetNetInfoEx(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries);
+BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData);
+HANDLE PacketGetReadEvent(LPADAPTER AdapterObject);
+BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len);
+BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks);
+BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync);
+BOOL PacketStopDriver();
+VOID PacketCloseAdapter(LPADAPTER lpAdapter);
+BOOLEAN PacketStartOem(PCHAR errorString, UINT errorStringLength);
+BOOLEAN PacketStartOemEx(PCHAR errorString, UINT errorStringLength, ULONG flags);
+PAirpcapHandle PacketGetAirPcapHandle(LPADAPTER AdapterObject);
+
+//
+// Used by PacketStartOemEx
+//
+#define PACKET_START_OEM_NO_NETMON 0x00000001
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__PACKET32
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/PacketData.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/PacketData.h
new file mode 100644
index 000000000..8124db66d
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/PacketData.h
@@ -0,0 +1,267 @@
+char pkt1[] = {
+0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14,
+0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00,
+0x00, 0x30, 0x09, 0x9c, 0x40, 0x00, 0x80, 0x06,
+0x6f, 0x07, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8,
+0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7,
+0xc7, 0x35, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02,
+0x40, 0x00, 0xdf, 0xab, 0x00, 0x00, 0x02, 0x04,
+0x05, 0xb4, 0x01, 0x01, 0x04, 0x02 };
+
+char pkt2[] = {
+0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01,
+0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00,
+0x00, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,
+0xf8, 0xa6, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8,
+0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00,
+0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12,
+0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04,
+0x05, 0x92 };
+
+char pkt3[] = {
+0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14,
+0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00,
+0x00, 0x28, 0x09, 0x9e, 0x40, 0x00, 0x80, 0x06,
+0x6f, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8,
+0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7,
+0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10,
+0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 };
+
+char pkt4[] = {
+0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14,
+0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00,
+0x02, 0x27, 0x09, 0x9f, 0x40, 0x00, 0x80, 0x06,
+0x6d, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8,
+0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7,
+0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18,
+0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45,
+0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50,
+0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63,
+0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d,
+0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c,
+0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78,
+0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70,
+0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f,
+0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d,
+0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65,
+0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69,
+0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76,
+0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78,
+0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70,
+0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c,
+0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
+0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64,
+0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65,
+0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20,
+0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
+0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73,
+0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
+0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70,
+0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78,
+0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70,
+0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d,
+0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d,
+0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70,
+0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d,
+0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a,
+0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c,
+0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a,
+0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a,
+0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45,
+0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a,
+0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64,
+0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a,
+0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65,
+0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69,
+0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20,
+0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69,
+0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49,
+0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57,
+0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e,
+0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53,
+0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67,
+0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e,
+0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32,
+0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37,
+0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43,
+0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30,
+0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38,
+0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43,
+0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32,
+0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48,
+0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32,
+0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31,
+0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
+0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b,
+0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76,
+0x65, 0x0d, 0x0a, 0x0d, 0x0a };
+
+char pkt5[] = {
+0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01,
+0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00,
+0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x40, 0x06,
+0xf8, 0xa5, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8,
+0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00,
+0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12,
+0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04,
+0x05, 0x92 };
+
+char pkt6[] = {
+0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14,
+0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00,
+0x00, 0x28, 0x09, 0xa1, 0x40, 0x00, 0x80, 0x06,
+0x6f, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8,
+0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7,
+0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10,
+0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 };
+
+char pkt7[] = {
+0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14,
+0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00,
+0x02, 0x27, 0x09, 0xa2, 0x40, 0x00, 0x80, 0x06,
+0x6d, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8,
+0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7,
+0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18,
+0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45,
+0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50,
+0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63,
+0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d,
+0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c,
+0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78,
+0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70,
+0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f,
+0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d,
+0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65,
+0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69,
+0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76,
+0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78,
+0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70,
+0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c,
+0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
+0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64,
+0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65,
+0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20,
+0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
+0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73,
+0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
+0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70,
+0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78,
+0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70,
+0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d,
+0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d,
+0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70,
+0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d,
+0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a,
+0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c,
+0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a,
+0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a,
+0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45,
+0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a,
+0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64,
+0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a,
+0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65,
+0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69,
+0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20,
+0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69,
+0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49,
+0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57,
+0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e,
+0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53,
+0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67,
+0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e,
+0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32,
+0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37,
+0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43,
+0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30,
+0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38,
+0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43,
+0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32,
+0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48,
+0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32,
+0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31,
+0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
+0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b,
+0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76,
+0x65, 0x0d, 0x0a, 0x0d, 0x0a };
+
+char pkt8[] = {
+0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01,
+0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00,
+0x00, 0x2c, 0x00, 0x03, 0x00, 0x00, 0x40, 0x06,
+0xf8, 0xa4, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8,
+0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00,
+0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12,
+0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04,
+0x05, 0x92 };
+
+char pkt9[] = {
+0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14,
+0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00,
+0x00, 0x28, 0x09, 0xa3, 0x40, 0x00, 0x80, 0x06,
+0x6f, 0x08, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8,
+0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7,
+0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10,
+0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 };
+
+char pkt10[] = {
+0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01,
+0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00,
+0x00, 0x2c, 0x00, 0x04, 0x00, 0x00, 0x40, 0x06,
+0xf8, 0xa3, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8,
+0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00,
+0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12,
+0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04,
+0x05, 0x92 };
+
+char pkt11[] = {
+0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14,
+0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00,
+0x00, 0x28, 0x09, 0xa6, 0x40, 0x00, 0x80, 0x06,
+0x6f, 0x05, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8,
+0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7,
+0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10,
+0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 };
+
+char pkt12[] = {
+0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14,
+0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00,
+0x00, 0x28, 0x09, 0xa7, 0x40, 0x00, 0x80, 0x06,
+0x6f, 0x04, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8,
+0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7,
+0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x14,
+0x00, 0x00, 0x43, 0xf4, 0x00, 0x00 };
+
+
+typedef struct
+{
+ char *pcData;
+ int iDataLen;
+} xPacketData;
+
+xPacketData xAllPackets[] =
+{
+ { pkt1, sizeof( pkt1 ) },
+// { pkt2, sizeof( pkt2 ) },
+ { pkt3, sizeof( pkt3 ) },
+ { pkt4, sizeof( pkt4 ) },
+// { pkt5, sizeof( pkt5 ) },
+ { pkt6, sizeof( pkt6 ) },
+ { pkt7, sizeof( pkt7 ) },
+ { pkt8, sizeof( pkt8 ) },
+ { pkt9, sizeof( pkt9 ) },
+ { pkt10, sizeof( pkt10 ) },
+// { pkt11, sizeof( pkt11 ) },
+// { pkt12, sizeof( pkt12 ) },
+// { pkt13, sizeof( pkt13 ) },
+// { pkt14, sizeof( pkt14 ) },
+// { pkt15, sizeof( pkt15 ) },
+// { pkt16, sizeof( pkt16 ) },
+};
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/Win32-Extensions.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/Win32-Extensions.h
new file mode 100644
index 000000000..be71c85e9
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/Win32-Extensions.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino, CACE Technologies
+ * nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef __WIN32_EXTENSIONS_H__
+#define __WIN32_EXTENSIONS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Definitions */
+
+/*!
+ \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit().
+*/
+struct pcap_send_queue
+{
+ u_int maxlen; ///< Maximum size of the the queue, in bytes. This variable contains the size of the buffer field.
+ u_int len; ///< Current size of the queue, in bytes.
+ char *buffer; ///< Buffer containing the packets to be sent.
+};
+
+typedef struct pcap_send_queue pcap_send_queue;
+
+/*!
+ \brief This typedef is a support for the pcap_get_airpcap_handle() function
+*/
+#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_)
+#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_
+typedef struct _AirpcapHandle *PAirpcapHandle;
+#endif
+
+#define BPF_MEM_EX_IMM 0xc0
+#define BPF_MEM_EX_IND 0xe0
+
+/*used for ST*/
+#define BPF_MEM_EX 0xc0
+#define BPF_TME 0x08
+
+#define BPF_LOOKUP 0x90
+#define BPF_EXECUTE 0xa0
+#define BPF_INIT 0xb0
+#define BPF_VALIDATE 0xc0
+#define BPF_SET_ACTIVE 0xd0
+#define BPF_RESET 0xe0
+#define BPF_SET_MEMORY 0x80
+#define BPF_GET_REGISTER_VALUE 0x70
+#define BPF_SET_REGISTER_VALUE 0x60
+#define BPF_SET_WORKING 0x50
+#define BPF_SET_ACTIVE_READ 0x40
+#define BPF_SET_AUTODELETION 0x30
+#define BPF_SEPARATION 0xff
+
+/* Prototypes */
+pcap_send_queue* pcap_sendqueue_alloc(u_int memsize);
+
+void pcap_sendqueue_destroy(pcap_send_queue* queue);
+
+int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data);
+
+u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync);
+
+HANDLE pcap_getevent(pcap_t *p);
+
+struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size);
+
+int pcap_setuserbuffer(pcap_t *p, int size);
+
+int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks);
+
+int pcap_live_dump_ended(pcap_t *p, int sync);
+
+int pcap_offline_filter(struct bpf_program *prog, const struct pcap_pkthdr *header, const u_char *pkt_data);
+
+int pcap_start_oem(char* err_str, int flags);
+
+PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__WIN32_EXTENSIONS_H__
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/arch.c b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/arch.c
new file mode 100644
index 000000000..c90f03006
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/arch.c
@@ -0,0 +1,378 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/* WinPCap includes. */
+#include "pcap.h"
+#include "remote-ext.h"
+
+/* uIP includes. */
+#include "net/uip.h"
+#include "net/uip_arp.h"
+#include "net/clock-arch.h"
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+/*
+ * Query the computer the simulation is being executed on to find the network
+ * interfaces it has installed.
+ */
+static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );
+
+/*
+ * Open the network interface. The number of the interface to be opened is set
+ * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
+ */
+static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces );
+
+/*
+ * Configure the capture filter to allow blocking reads, and to filter out
+ * packets that are not of interest to this demo.
+ */
+static void prvConfigureCaptureBehaviour( void );
+
+pcap_t *pxOpenedInterfaceHandle = NULL;
+LARGE_INTEGER freq, sys_start_time;
+
+#define archNUM_BUFFERS 5
+#define archNUM_BUFFER_POINTERS ( archNUM_BUFFERS - 1 )
+
+static void prvInterruptSimulator( void *pvParameters );
+
+static unsigned char ucEthernetBuffer[ archNUM_BUFFERS ][ UIP_CONF_BUFFER_SIZE ];
+static unsigned char *pucEthernetBufferPointers[ archNUM_BUFFER_POINTERS ];
+
+static long lLengthOfDataInBuffer[ archNUM_BUFFER_POINTERS ] = { 0 };
+static unsigned char ucNextBufferToFill = 0U, ucNextBufferToProcess = 0U;
+
+unsigned char *uip_buf = NULL;
+char cErrorBuffer[PCAP_ERRBUF_SIZE];
+
+void vNetifTx( void )
+{
+ pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len );
+ pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len );
+}
+/*-----------------------------------------------------------*/
+
+UBaseType_t uxNetifRx( void )
+{
+UBaseType_t xDataLen;
+unsigned char *pucTemp;
+
+ /* Check there is really data available. */
+ xDataLen = lLengthOfDataInBuffer[ ucNextBufferToProcess ];
+ if( xDataLen != 0L )
+ {
+
+ /* The buffer pointed to by uip_buf is going to change. Remember which
+ buffer uip_buf is currently pointing to. */
+ pucTemp = uip_buf;
+
+ /* Point uip_buf at the next buffer that contains data. */
+ uip_buf = pucEthernetBufferPointers[ ucNextBufferToProcess ];
+
+ /* The buffer pointed to by
+ pucEthernetBufferPointeres[ ucNextBufferToProcess ] is now in use by
+ uip_buf, but the buffer uip_buf was pointing to on entry to this
+ function is free. Set
+ pucEthernetBufferPointeres[ ucNextBufferToProcess ] to the free
+ buffer. */
+ pucEthernetBufferPointers[ ucNextBufferToProcess ] = pucTemp;
+ lLengthOfDataInBuffer[ ucNextBufferToProcess ] = 0L;
+
+ ucNextBufferToProcess++;
+ if( ucNextBufferToProcess >= archNUM_BUFFER_POINTERS )
+ {
+ ucNextBufferToProcess = 0L;
+ }
+ }
+
+ return xDataLen;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetifInit( void )
+{
+BaseType_t x;
+pcap_if_t *pxAllNetworkInterfaces;
+
+ /* Allocate a free buffer to each buffer pointer. */
+ for( x = 0; x < sizeof( pucEthernetBufferPointers ) / sizeof( unsigned char * ); x++ )
+ {
+ pucEthernetBufferPointers[ x ] = &( ucEthernetBuffer[ x ][ 0 ] );
+ }
+
+ /* Start with uip_buf pointing to a buffer that is not referenced from the
+ pucEthernetBufferPointers[] array. */
+ uip_buf = &( ucEthernetBuffer[ archNUM_BUFFERS - 1 ][ 0 ] );
+
+ /* Query the computer the simulation is being executed on to find the
+ network interfaces it has installed. */
+ pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();
+
+ /* Open the network interface. The number of the interface to be opened is
+ set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
+ Calling this function will set the pxOpenedInterfaceHandle variable. If,
+ after calling this function, pxOpenedInterfaceHandle is equal to NULL, then
+ the interface could not be opened. */
+ if( pxAllNetworkInterfaces != NULL )
+ {
+ prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );
+ }
+
+
+ return x;
+}
+/*-----------------------------------------------------------*/
+
+static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )
+{
+pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface;
+long lInterfaceNumber = 1;
+
+ if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )
+ {
+ printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer );
+ pxAllNetworkInterfaces = NULL;
+ }
+
+ if( pxAllNetworkInterfaces != NULL )
+ {
+ /* Print out the list of network interfaces. The first in the list
+ is interface '1', not interface '0'. */
+ for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )
+ {
+ printf( "%d. %s", lInterfaceNumber, xInterface->name );
+
+ if( xInterface->description != NULL )
+ {
+ printf( " (%s)\r\n", xInterface->description );
+ }
+ else
+ {
+ printf( " (No description available)\r\n") ;
+ }
+
+ lInterfaceNumber++;
+ }
+ }
+
+ if( lInterfaceNumber == 1 )
+ {
+ /* The interface number was never incremented, so the above for() loop
+ did not execute meaning no interfaces were found. */
+ printf( " \r\nNo network interfaces were found.\r\n" );
+ pxAllNetworkInterfaces = NULL;
+ }
+
+ printf( "\r\nThe interface that will be opened is set by configNETWORK_INTERFACE_TO_USE which should be defined in FreeRTOSConfig.h\r\n" );
+ printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE );
+
+ if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) )
+ {
+ printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" );
+
+ if( pxAllNetworkInterfaces != NULL )
+ {
+ /* Free the device list, as no devices are going to be opened. */
+ pcap_freealldevs( pxAllNetworkInterfaces );
+ pxAllNetworkInterfaces = NULL;
+ }
+ }
+
+ return pxAllNetworkInterfaces;
+}
+/*-----------------------------------------------------------*/
+
+static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces )
+{
+pcap_if_t *xInterface;
+long x;
+
+ /* Walk the list of devices until the selected device is located. */
+ xInterface = pxAllNetworkInterfaces;
+ for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ )
+ {
+ xInterface = xInterface->next;
+ }
+
+ /* Open the selected interface. */
+ pxOpenedInterfaceHandle = pcap_open( xInterface->name, /* The name of the selected interface. */
+ UIP_CONF_BUFFER_SIZE, /* The size of the packet to capture. */
+ PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscious mode as the MAC and
+ IP address is going to be "simulated", and
+ not be the real MAC and IP address. This allows
+ trafic to the simulated IP address to be routed
+ to uIP, and trafic to the real IP address to be
+ routed to the Windows TCP/IP stack. */
+ 0xfffffffL, /* The read time out. This is going to block
+ until data is available. */
+ NULL, /* No authentication is required as this is
+ not a remote capture session. */
+ cErrorBuffer
+ );
+
+ if ( pxOpenedInterfaceHandle == NULL )
+ {
+ printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name );
+ }
+ else
+ {
+ /* Configure the capture filter to allow blocking reads, and to filter
+ out packets that are not of interest to this demo. */
+ prvConfigureCaptureBehaviour();
+ }
+
+ /* The device list is no longer required. */
+ pcap_freealldevs( pxAllNetworkInterfaces );
+}
+/*-----------------------------------------------------------*/
+
+static void prvConfigureCaptureBehaviour( void )
+{
+struct bpf_program xFilterCode;
+const long lMinBytesToCopy = 10L, lBlocking = 0L;
+unsigned long ulNetMask;
+
+ /* Unblock a read as soon as anything is received. */
+ pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy );
+
+ /* Allow blocking. */
+ pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer );
+
+ /* Set up a filter so only the packets of interest are passed to the uIP
+ stack. cErrorBuffer is used for convenience to create the string. Don't
+ confuse this with an error message. */
+ sprintf( cErrorBuffer, "broadcast or multicast or host %d.%d.%d.%d", configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 );
+
+ ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;
+
+ if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )
+ {
+ printf("\r\nThe packet filter string is invalid\r\n" );
+ }
+ else
+ {
+ if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )
+ {
+ printf( "\r\nAn error occurred setting the packet filter.\r\n" );
+ }
+ }
+
+ /* Create a task that simulates an interrupt in a real system. This will
+ block waiting for packets, then send a message to the uIP task when data
+ is available. */
+ xTaskCreate( prvInterruptSimulator, ( signed char * ) "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, ( configuIP_TASK_PRIORITY - 1 ), NULL );
+}
+/*-----------------------------------------------------------*/
+
+static void prvInterruptSimulator( void *pvParameters )
+{
+static struct pcap_pkthdr *pxHeader;
+const unsigned char *pucPacketData;
+extern QueueHandle_t xEMACEventQueue;
+const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;
+long lResult;
+
+ /* Just to kill the compiler warning. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* Get the next packet. */
+ lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData );
+ if( lResult )
+ {
+ /* Is the next buffer into which data should be placed free? */
+ if( lLengthOfDataInBuffer[ ucNextBufferToFill ] == 0L )
+ {
+ /* Copy the data from the captured packet into the buffer. */
+ memcpy( pucEthernetBufferPointers[ ucNextBufferToFill ], pucPacketData, pxHeader->len );
+
+ /* Note the amount of data that was copied. */
+ lLengthOfDataInBuffer[ ucNextBufferToFill ] = pxHeader->len;
+
+ /* Move onto the next buffer, wrapping around if necessary. */
+ ucNextBufferToFill++;
+ if( ucNextBufferToFill >= archNUM_BUFFER_POINTERS )
+ {
+ ucNextBufferToFill = 0U;
+ }
+
+ /* Data was received and stored. Send a message to the uIP task
+ to let it know. */
+ xQueueSendToBack( xEMACEventQueue, &ulRxEvent, portMAX_DELAY );
+ }
+ }
+ }
+}
+
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/bittypes.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/bittypes.h
new file mode 100644
index 000000000..f55fcecfd
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/bittypes.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _BITTYPES_H
+#define _BITTYPES_H
+
+#ifndef HAVE_U_INT8_T
+
+#if SIZEOF_CHAR == 1
+typedef unsigned char u_int8_t;
+typedef signed char _int8_t;
+#elif SIZEOF_INT == 1
+typedef unsigned int u_int8_t;
+typedef signed int int8_t;
+#else /* XXX */
+#error "there's no appropriate type for u_int8_t"
+#endif
+#define HAVE_U_INT8_T 1
+#define HAVE_INT8_T 1
+
+#endif /* HAVE_U_INT8_T */
+
+#ifndef HAVE_U_INT16_T
+
+#if SIZEOF_SHORT == 2
+typedef unsigned short u_int16_t;
+typedef signed short _int16_t;
+#elif SIZEOF_INT == 2
+typedef unsigned int u_int16_t;
+typedef signed int int16_t;
+#elif SIZEOF_CHAR == 2
+typedef unsigned char u_int16_t;
+typedef signed char int16_t;
+#else /* XXX */
+#error "there's no appropriate type for u_int16_t"
+#endif
+#define HAVE_U_INT16_T 1
+#define HAVE_INT16_T 1
+
+#endif /* HAVE_U_INT16_T */
+
+#ifndef HAVE_U_INT32_T
+
+#if SIZEOF_INT == 4
+typedef unsigned int u_int32_t;
+typedef signed int _int32_t;
+#elif SIZEOF_LONG == 4
+typedef unsigned long u_int32_t;
+typedef signed long int32_t;
+#elif SIZEOF_SHORT == 4
+typedef unsigned short u_int32_t;
+typedef signed short int32_t;
+#else /* XXX */
+#error "there's no appropriate type for u_int32_t"
+#endif
+#define HAVE_U_INT32_T 1
+#define HAVE_INT32_T 1
+
+#endif /* HAVE_U_INT32_T */
+
+#ifndef HAVE_U_INT64_T
+#if SIZEOF_LONG_LONG == 8
+typedef unsigned long long u_int64_t;
+typedef long long int64_t;
+#elif defined(_MSC_EXTENSIONS)
+typedef unsigned _int64 u_int64_t;
+typedef _int64 int64_t;
+#elif SIZEOF_INT == 8
+typedef unsigned int u_int64_t;
+#elif SIZEOF_LONG == 8
+typedef unsigned long u_int64_t;
+#elif SIZEOF_SHORT == 8
+typedef unsigned short u_int64_t;
+#else /* XXX */
+#error "there's no appropriate type for u_int64_t"
+#endif
+
+#endif /* HAVE_U_INT64_T */
+
+#ifndef PRId64
+#ifdef _MSC_EXTENSIONS
+#define PRId64 "I64d"
+#else /* _MSC_EXTENSIONS */
+#define PRId64 "lld"
+#endif /* _MSC_EXTENSIONS */
+#endif /* PRId64 */
+
+#ifndef PRIo64
+#ifdef _MSC_EXTENSIONS
+#define PRIo64 "I64o"
+#else /* _MSC_EXTENSIONS */
+#define PRIo64 "llo"
+#endif /* _MSC_EXTENSIONS */
+#endif /* PRIo64 */
+
+#ifndef PRIx64
+#ifdef _MSC_EXTENSIONS
+#define PRIx64 "I64x"
+#else /* _MSC_EXTENSIONS */
+#define PRIx64 "llx"
+#endif /* _MSC_EXTENSIONS */
+#endif /* PRIx64 */
+
+#ifndef PRIu64
+#ifdef _MSC_EXTENSIONS
+#define PRIu64 "I64u"
+#else /* _MSC_EXTENSIONS */
+#define PRIu64 "llu"
+#endif /* _MSC_EXTENSIONS */
+#endif /* PRIu64 */
+
+#endif /* _BITTYPES_H */
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/ip6_misc.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/ip6_misc.h
new file mode 100644
index 000000000..562fa6184
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/ip6_misc.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 1993, 1994, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/Win32/Include/ip6_misc.h,v 1.5 2006-01-22 18:02:18 gianluca Exp $ (LBL)
+ */
+
+/*
+ * This file contains a collage of declarations for IPv6 from FreeBSD not present in Windows
+ */
+
+#include <winsock2.h>
+
+#include <ws2tcpip.h>
+
+#ifndef __MINGW32__
+#define IN_MULTICAST(a) IN_CLASSD(a)
+#endif
+
+#define IN_EXPERIMENTAL(a) ((((u_int32_t) (a)) & 0xf0000000) == 0xf0000000)
+
+#define IN_LOOPBACKNET 127
+
+#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)
+/* IPv6 address */
+struct in6_addr
+ {
+ union
+ {
+ u_int8_t u6_addr8[16];
+ u_int16_t u6_addr16[8];
+ u_int32_t u6_addr32[4];
+ } in6_u;
+#define s6_addr in6_u.u6_addr8
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+#define s6_addr64 in6_u.u6_addr64
+ };
+
+#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
+#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }
+#endif /* __MINGW32__ */
+
+
+#if (defined _MSC_VER) || (defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF))
+typedef unsigned short sa_family_t;
+#endif
+
+
+#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)
+
+#define __SOCKADDR_COMMON(sa_prefix) \
+ sa_family_t sa_prefix##family
+
+/* Ditto, for IPv6. */
+struct sockaddr_in6
+ {
+ __SOCKADDR_COMMON (sin6_);
+ u_int16_t sin6_port; /* Transport layer port # */
+ u_int32_t sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ };
+
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \
+ (((u_int32_t *) (a))[2] == htonl (0xffff)))
+
+#define IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff)
+
+#define IN6_IS_ADDR_LINKLOCAL(a) \
+ ((((u_int32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000))
+
+#define IN6_IS_ADDR_LOOPBACK(a) \
+ (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \
+ ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1))
+#endif /* __MINGW32__ */
+
+#define ip6_vfc ip6_ctlun.ip6_un2_vfc
+#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
+#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
+#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
+#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
+#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
+
+#define nd_rd_type nd_rd_hdr.icmp6_type
+#define nd_rd_code nd_rd_hdr.icmp6_code
+#define nd_rd_cksum nd_rd_hdr.icmp6_cksum
+#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0]
+
+/*
+ * IPV6 extension headers
+ */
+#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */
+#define IPPROTO_IPV6 41 /* IPv6 header. */
+#define IPPROTO_ROUTING 43 /* IPv6 routing header */
+#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */
+#define IPPROTO_ESP 50 /* encapsulating security payload */
+#define IPPROTO_AH 51 /* authentication header */
+#define IPPROTO_ICMPV6 58 /* ICMPv6 */
+#define IPPROTO_NONE 59 /* IPv6 no next header */
+#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */
+#define IPPROTO_PIM 103 /* Protocol Independent Multicast. */
+
+#define IPV6_RTHDR_TYPE_0 0
+
+/* Option types and related macros */
+#define IP6OPT_PAD1 0x00 /* 00 0 00000 */
+#define IP6OPT_PADN 0x01 /* 00 0 00001 */
+#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */
+#define IP6OPT_JUMBO_LEN 6
+#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */
+
+#define IP6OPT_RTALERT_LEN 4
+#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */
+#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */
+#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */
+#define IP6OPT_MINLEN 2
+
+#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */
+#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */
+#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */
+#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */
+#define IP6OPT_EID 0x8a /* 10 0 01010 */
+
+#define IP6OPT_TYPE(o) ((o) & 0xC0)
+#define IP6OPT_TYPE_SKIP 0x00
+#define IP6OPT_TYPE_DISCARD 0x40
+#define IP6OPT_TYPE_FORCEICMP 0x80
+#define IP6OPT_TYPE_ICMP 0xC0
+
+#define IP6OPT_MUTABLE 0x20
+
+
+#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)
+#ifndef EAI_ADDRFAMILY
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+#endif
+#endif /* __MINGW32__ */
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/netif.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/netif.h
new file mode 100644
index 000000000..6982ca09c
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/netif.h
@@ -0,0 +1,94 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+#ifndef NET_IF_H
+#define NET_IF_H
+
+/*
+ * Send uip_len bytes from uip_buf to the network interface selected by the
+ * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h).
+ */
+void vNetifTx( void );
+
+/*
+ * Receive bytes from the network interface selected by the
+ * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). The
+ * bytes are placed in uip_buf. The number of bytes copied into uip_buf is
+ * returned.
+ */
+UBaseType_t uxNetifRx( void );
+
+/*
+ * Prepare a packet capture session. This will print out all the network
+ * interfaces available, and the one actually used is set by the
+ * configNETWORK_INTERFACE_TO_USE constant that is defined in
+ * FreeRTOSConfig.h. */
+BaseType_t xNetifInit( void );
+
+#endif /* NET_IF_H */
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-bpf.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-bpf.h
new file mode 100644
index 000000000..5fe129dbb
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-bpf.h
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.50 2007/04/01 21:43:55 guy Exp $ (LBL)
+ */
+
+/*
+ * For backwards compatibility.
+ *
+ * Note to OS vendors: do NOT get rid of this file! Some applications
+ * might expect to be able to include <pcap-bpf.h>.
+ */
+#include <pcap/bpf.h>
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-namedb.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-namedb.h
new file mode 100644
index 000000000..80a2f0040
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-namedb.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1994, 1996
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.13 2006/10/04 18:13:32 guy Exp $ (LBL)
+ */
+
+/*
+ * For backwards compatibility.
+ *
+ * Note to OS vendors: do NOT get rid of this file! Some applications
+ * might expect to be able to include <pcap-namedb.h>.
+ */
+#include <pcap/namedb.h>
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-stdinc.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-stdinc.h
new file mode 100644
index 000000000..cbd62d169
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap-stdinc.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-stdinc.h,v 1.10.2.1 2008-10-06 15:38:39 gianluca Exp $ (LBL)
+ */
+
+#define SIZEOF_CHAR 1
+#define SIZEOF_SHORT 2
+#define SIZEOF_INT 4
+#ifndef _MSC_EXTENSIONS
+#define SIZEOF_LONG_LONG 8
+#endif
+
+/*
+ * Avoids a compiler warning in case this was already defined
+ * (someone defined _WINSOCKAPI_ when including 'windows.h', in order
+ * to prevent it from including 'winsock.h')
+ */
+#ifdef _WINSOCKAPI_
+#undef _WINSOCKAPI_
+#endif
+#include <winsock2.h>
+
+#include <fcntl.h>
+
+#include "bittypes.h"
+#include <time.h>
+#include <io.h>
+
+#ifndef __MINGW32__
+#include "IP6_misc.h"
+#endif
+
+#define caddr_t char*
+
+#if _MSC_VER < 1500
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#define strdup _strdup
+#endif
+
+#define inline __inline
+
+#ifdef __MINGW32__
+#include <stdint.h>
+#else /*__MINGW32__*/
+/* MSVC compiler */
+#ifndef _UINTPTR_T_DEFINED
+#ifdef _WIN64
+typedef unsigned __int64 uintptr_t;
+#else
+typedef _W64 unsigned int uintptr_t;
+#endif
+#define _UINTPTR_T_DEFINED
+#endif
+
+#ifndef _INTPTR_T_DEFINED
+#ifdef _WIN64
+typedef __int64 intptr_t;
+#else
+typedef _W64 int intptr_t;
+#endif
+#define _INTPTR_T_DEFINED
+#endif
+
+#endif /*__MINGW32__*/
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap.h
new file mode 100644
index 000000000..935f9494c
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.59 2006/10/04 18:09:22 guy Exp $ (LBL)
+ */
+
+/*
+ * For backwards compatibility.
+ *
+ * Note to OS vendors: do NOT get rid of this file! Many applications
+ * expect to be able to include <pcap.h>, and at least some of them
+ * go through contortions in their configure scripts to try to detect
+ * OSes that have "helpfully" moved pcap.h to <pcap/pcap.h> without
+ * leaving behind a <pcap.h> file.
+ */
+#include <pcap/pcap.h>
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/bluetooth.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/bluetooth.h
new file mode 100644
index 000000000..7bf65df03
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/bluetooth.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2006 Paolo Abeni (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * bluetooth data struct
+ * By Paolo Abeni <paolo.abeni@email.it>
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap/bluetooth.h,v 1.1 2007/09/22 02:10:17 guy Exp $
+ */
+
+#ifndef _PCAP_BLUETOOTH_STRUCTS_H__
+#define _PCAP_BLUETOOTH_STRUCTS_H__
+
+/*
+ * Header prepended libpcap to each bluetooth h:4 frame.
+ * fields are in network byte order
+ */
+typedef struct _pcap_bluetooth_h4_header {
+ u_int32_t direction; /* if first bit is set direction is incoming */
+} pcap_bluetooth_h4_header;
+
+
+#endif
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/bpf.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/bpf.h
new file mode 100644
index 000000000..9f4ca33e3
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/bpf.h
@@ -0,0 +1,934 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf.h 7.1 (Berkeley) 5/7/91
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.19.2.8 2008-09-22 20:16:01 guy Exp $ (LBL)
+ */
+
+/*
+ * This is libpcap's cut-down version of bpf.h; it includes only
+ * the stuff needed for the code generator and the userland BPF
+ * interpreter, and the libpcap APIs for setting filters, etc..
+ *
+ * "pcap-bpf.c" will include the native OS version, as it deals with
+ * the OS's BPF implementation.
+ *
+ * XXX - should this all just be moved to "pcap.h"?
+ */
+
+#ifndef BPF_MAJOR_VERSION
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* BSD style release date */
+#define BPF_RELEASE 199606
+
+#ifdef MSDOS /* must be 32-bit */
+typedef long bpf_int32;
+typedef unsigned long bpf_u_int32;
+#else
+typedef int bpf_int32;
+typedef u_int bpf_u_int32;
+#endif
+
+/*
+ * Alignment macros. BPF_WORDALIGN rounds up to the next
+ * even multiple of BPF_ALIGNMENT.
+ */
+#ifndef __NetBSD__
+#define BPF_ALIGNMENT sizeof(bpf_int32)
+#else
+#define BPF_ALIGNMENT sizeof(long)
+#endif
+#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1))
+
+#define BPF_MAXBUFSIZE 0x8000
+#define BPF_MINBUFSIZE 32
+
+/*
+ * Structure for "pcap_compile()", "pcap_setfilter()", etc..
+ */
+struct bpf_program {
+ u_int bf_len;
+ struct bpf_insn *bf_insns;
+};
+
+/*
+ * Struct return by BIOCVERSION. This represents the version number of
+ * the filter language described by the instruction encodings below.
+ * bpf understands a program iff kernel_major == filter_major &&
+ * kernel_minor >= filter_minor, that is, if the value returned by the
+ * running kernel has the same major number and a minor number equal
+ * equal to or less than the filter being downloaded. Otherwise, the
+ * results are undefined, meaning an error may be returned or packets
+ * may be accepted haphazardly.
+ * It has nothing to do with the source code version.
+ */
+struct bpf_version {
+ u_short bv_major;
+ u_short bv_minor;
+};
+/* Current version number of filter architecture. */
+#define BPF_MAJOR_VERSION 1
+#define BPF_MINOR_VERSION 1
+
+/*
+ * Data-link level type codes.
+ *
+ * Do *NOT* add new values to this list without asking
+ * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run
+ * the risk of using a value that's already being used for some other
+ * purpose, and of having tools that read libpcap-format captures not
+ * being able to handle captures with your new DLT_ value, with no hope
+ * that they will ever be changed to do so (as that would destroy their
+ * ability to read captures using that value for that other purpose).
+ */
+
+/*
+ * These are the types that are the same on all platforms, and that
+ * have been defined by <net/bpf.h> for ages.
+ */
+#define DLT_NULL 0 /* BSD loopback encapsulation */
+#define DLT_EN10MB 1 /* Ethernet (10Mb) */
+#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */
+#define DLT_AX25 3 /* Amateur Radio AX.25 */
+#define DLT_PRONET 4 /* Proteon ProNET Token Ring */
+#define DLT_CHAOS 5 /* Chaos */
+#define DLT_IEEE802 6 /* 802.5 Token Ring */
+#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */
+#define DLT_SLIP 8 /* Serial Line IP */
+#define DLT_PPP 9 /* Point-to-point Protocol */
+#define DLT_FDDI 10 /* FDDI */
+
+/*
+ * These are types that are different on some platforms, and that
+ * have been defined by <net/bpf.h> for ages. We use #ifdefs to
+ * detect the BSDs that define them differently from the traditional
+ * libpcap <net/bpf.h>
+ *
+ * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS,
+ * but I don't know what the right #define is for BSD/OS.
+ */
+#define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */
+
+#ifdef __OpenBSD__
+#define DLT_RAW 14 /* raw IP */
+#else
+#define DLT_RAW 12 /* raw IP */
+#endif
+
+/*
+ * Given that the only OS that currently generates BSD/OS SLIP or PPP
+ * is, well, BSD/OS, arguably everybody should have chosen its values
+ * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they
+ * didn't. So it goes.
+ */
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+#ifndef DLT_SLIP_BSDOS
+#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */
+#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */
+#endif
+#else
+#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */
+#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */
+#endif
+
+/*
+ * 17 is used for DLT_OLD_PFLOG in OpenBSD;
+ * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below.
+ * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else.
+ */
+
+#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */
+
+/*
+ * Apparently Redback uses this for its SmartEdge 400/800. I hope
+ * nobody else decided to use it, too.
+ */
+#define DLT_REDBACK_SMARTEDGE 32
+
+/*
+ * These values are defined by NetBSD; other platforms should refrain from
+ * using them for other purposes, so that NetBSD savefiles with link
+ * types of 50 or 51 can be read as this type on all platforms.
+ */
+#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */
+#define DLT_PPP_ETHER 51 /* PPP over Ethernet */
+
+/*
+ * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses
+ * a link-layer type of 99 for the tcpdump it supplies. The link-layer
+ * header has 6 bytes of unknown data, something that appears to be an
+ * Ethernet type, and 36 bytes that appear to be 0 in at least one capture
+ * I've seen.
+ */
+#define DLT_SYMANTEC_FIREWALL 99
+
+/*
+ * Values between 100 and 103 are used in capture file headers as
+ * link-layer types corresponding to DLT_ types that differ
+ * between platforms; don't use those values for new DLT_ new types.
+ */
+
+/*
+ * This value was defined by libpcap 0.5; platforms that have defined
+ * it with a different value should define it here with that value -
+ * a link type of 104 in a save file will be mapped to DLT_C_HDLC,
+ * whatever value that happens to be, so programs will correctly
+ * handle files with that link type regardless of the value of
+ * DLT_C_HDLC.
+ *
+ * The name DLT_C_HDLC was used by BSD/OS; we use that name for source
+ * compatibility with programs written for BSD/OS.
+ *
+ * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well,
+ * for source compatibility with programs written for libpcap 0.5.
+ */
+#define DLT_C_HDLC 104 /* Cisco HDLC */
+#define DLT_CHDLC DLT_C_HDLC
+
+#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */
+
+/*
+ * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW,
+ * except when it isn't. (I.e., sometimes it's just raw IP, and
+ * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL,
+ * so that we don't have to worry about the link-layer header.)
+ */
+
+/*
+ * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides
+ * with other values.
+ * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header
+ * (DLCI, etc.).
+ */
+#define DLT_FRELAY 107
+
+/*
+ * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except
+ * that the AF_ type in the link-layer header is in network byte order.
+ *
+ * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so
+ * we don't use 12 for it in OSes other than OpenBSD.
+ */
+#ifdef __OpenBSD__
+#define DLT_LOOP 12
+#else
+#define DLT_LOOP 108
+#endif
+
+/*
+ * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's
+ * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other
+ * than OpenBSD.
+ */
+#ifdef __OpenBSD__
+#define DLT_ENC 13
+#else
+#define DLT_ENC 109
+#endif
+
+/*
+ * Values between 110 and 112 are reserved for use in capture file headers
+ * as link-layer types corresponding to DLT_ types that might differ
+ * between platforms; don't use those values for new DLT_ types
+ * other than the corresponding DLT_ types.
+ */
+
+/*
+ * This is for Linux cooked sockets.
+ */
+#define DLT_LINUX_SLL 113
+
+/*
+ * Apple LocalTalk hardware.
+ */
+#define DLT_LTALK 114
+
+/*
+ * Acorn Econet.
+ */
+#define DLT_ECONET 115
+
+/*
+ * Reserved for use with OpenBSD ipfilter.
+ */
+#define DLT_IPFILTER 116
+
+/*
+ * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023
+ * in SuSE 6.3, so we can't use 17 for it in capture-file headers.
+ *
+ * XXX: is there a conflict with DLT_PFSYNC 18 as well?
+ */
+#ifdef __OpenBSD__
+#define DLT_OLD_PFLOG 17
+#define DLT_PFSYNC 18
+#endif
+#define DLT_PFLOG 117
+
+/*
+ * Registered for Cisco-internal use.
+ */
+#define DLT_CISCO_IOS 118
+
+/*
+ * For 802.11 cards using the Prism II chips, with a link-layer
+ * header including Prism monitor mode information plus an 802.11
+ * header.
+ */
+#define DLT_PRISM_HEADER 119
+
+/*
+ * Reserved for Aironet 802.11 cards, with an Aironet link-layer header
+ * (see Doug Ambrisko's FreeBSD patches).
+ */
+#define DLT_AIRONET_HEADER 120
+
+/*
+ * Reserved for Siemens HiPath HDLC.
+ */
+#define DLT_HHDLC 121
+
+/*
+ * This is for RFC 2625 IP-over-Fibre Channel.
+ *
+ * This is not for use with raw Fibre Channel, where the link-layer
+ * header starts with a Fibre Channel frame header; it's for IP-over-FC,
+ * where the link-layer header starts with an RFC 2625 Network_Header
+ * field.
+ */
+#define DLT_IP_OVER_FC 122
+
+/*
+ * This is for Full Frontal ATM on Solaris with SunATM, with a
+ * pseudo-header followed by an AALn PDU.
+ *
+ * There may be other forms of Full Frontal ATM on other OSes,
+ * with different pseudo-headers.
+ *
+ * If ATM software returns a pseudo-header with VPI/VCI information
+ * (and, ideally, packet type information, e.g. signalling, ILMI,
+ * LANE, LLC-multiplexed traffic, etc.), it should not use
+ * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump
+ * and the like don't have to infer the presence or absence of a
+ * pseudo-header and the form of the pseudo-header.
+ */
+#define DLT_SUNATM 123 /* Solaris+SunATM */
+
+/*
+ * Reserved as per request from Kent Dahlgren <kent@praesum.com>
+ * for private use.
+ */
+#define DLT_RIO 124 /* RapidIO */
+#define DLT_PCI_EXP 125 /* PCI Express */
+#define DLT_AURORA 126 /* Xilinx Aurora link layer */
+
+/*
+ * Header for 802.11 plus a number of bits of link-layer information
+ * including radio information, used by some recent BSD drivers as
+ * well as the madwifi Atheros driver for Linux.
+ */
+#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */
+
+/*
+ * Reserved for the TZSP encapsulation, as per request from
+ * Chris Waters <chris.waters@networkchemistry.com>
+ * TZSP is a generic encapsulation for any other link type,
+ * which includes a means to include meta-information
+ * with the packet, e.g. signal strength and channel
+ * for 802.11 packets.
+ */
+#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */
+
+/*
+ * BSD's ARCNET headers have the source host, destination host,
+ * and type at the beginning of the packet; that's what's handed
+ * up to userland via BPF.
+ *
+ * Linux's ARCNET headers, however, have a 2-byte offset field
+ * between the host IDs and the type; that's what's handed up
+ * to userland via PF_PACKET sockets.
+ *
+ * We therefore have to have separate DLT_ values for them.
+ */
+#define DLT_ARCNET_LINUX 129 /* ARCNET */
+
+/*
+ * Juniper-private data link types, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, etc..
+ */
+#define DLT_JUNIPER_MLPPP 130
+#define DLT_JUNIPER_MLFR 131
+#define DLT_JUNIPER_ES 132
+#define DLT_JUNIPER_GGSN 133
+#define DLT_JUNIPER_MFR 134
+#define DLT_JUNIPER_ATM2 135
+#define DLT_JUNIPER_SERVICES 136
+#define DLT_JUNIPER_ATM1 137
+
+/*
+ * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund
+ * <dieter@apple.com>. The header that's presented is an Ethernet-like
+ * header:
+ *
+ * #define FIREWIRE_EUI64_LEN 8
+ * struct firewire_header {
+ * u_char firewire_dhost[FIREWIRE_EUI64_LEN];
+ * u_char firewire_shost[FIREWIRE_EUI64_LEN];
+ * u_short firewire_type;
+ * };
+ *
+ * with "firewire_type" being an Ethernet type value, rather than,
+ * for example, raw GASP frames being handed up.
+ */
+#define DLT_APPLE_IP_OVER_IEEE1394 138
+
+/*
+ * Various SS7 encapsulations, as per a request from Jeff Morriss
+ * <jeff.morriss[AT]ulticom.com> and subsequent discussions.
+ */
+#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */
+#define DLT_MTP2 140 /* MTP2, without pseudo-header */
+#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */
+#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */
+
+/*
+ * DOCSIS MAC frames.
+ */
+#define DLT_DOCSIS 143
+
+/*
+ * Linux-IrDA packets. Protocol defined at http://www.irda.org.
+ * Those packets include IrLAP headers and above (IrLMP...), but
+ * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy
+ * framing can be handled by the hardware and depend on the bitrate.
+ * This is exactly the format you would get capturing on a Linux-IrDA
+ * interface (irdaX), but not on a raw serial port.
+ * Note the capture is done in "Linux-cooked" mode, so each packet include
+ * a fake packet header (struct sll_header). This is because IrDA packet
+ * decoding is dependant on the direction of the packet (incomming or
+ * outgoing).
+ * When/if other platform implement IrDA capture, we may revisit the
+ * issue and define a real DLT_IRDA...
+ * Jean II
+ */
+#define DLT_LINUX_IRDA 144
+
+/*
+ * Reserved for IBM SP switch and IBM Next Federation switch.
+ */
+#define DLT_IBM_SP 145
+#define DLT_IBM_SN 146
+
+/*
+ * Reserved for private use. If you have some link-layer header type
+ * that you want to use within your organization, with the capture files
+ * using that link-layer header type not ever be sent outside your
+ * organization, you can use these values.
+ *
+ * No libpcap release will use these for any purpose, nor will any
+ * tcpdump release use them, either.
+ *
+ * Do *NOT* use these in capture files that you expect anybody not using
+ * your private versions of capture-file-reading tools to read; in
+ * particular, do *NOT* use them in products, otherwise you may find that
+ * people won't be able to use tcpdump, or snort, or Ethereal, or... to
+ * read capture files from your firewall/intrusion detection/traffic
+ * monitoring/etc. appliance, or whatever product uses that DLT_ value,
+ * and you may also find that the developers of those applications will
+ * not accept patches to let them read those files.
+ *
+ * Also, do not use them if somebody might send you a capture using them
+ * for *their* private type and tools using them for *your* private type
+ * would have to read them.
+ *
+ * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value,
+ * as per the comment above, and use the type you're given.
+ */
+#define DLT_USER0 147
+#define DLT_USER1 148
+#define DLT_USER2 149
+#define DLT_USER3 150
+#define DLT_USER4 151
+#define DLT_USER5 152
+#define DLT_USER6 153
+#define DLT_USER7 154
+#define DLT_USER8 155
+#define DLT_USER9 156
+#define DLT_USER10 157
+#define DLT_USER11 158
+#define DLT_USER12 159
+#define DLT_USER13 160
+#define DLT_USER14 161
+#define DLT_USER15 162
+
+/*
+ * For future use with 802.11 captures - defined by AbsoluteValue
+ * Systems to store a number of bits of link-layer information
+ * including radio information:
+ *
+ * http://www.shaftnet.org/~pizza/software/capturefrm.txt
+ *
+ * but it might be used by some non-AVS drivers now or in the
+ * future.
+ */
+#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, etc..
+ */
+#define DLT_JUNIPER_MONITOR 164
+
+/*
+ * Reserved for BACnet MS/TP.
+ */
+#define DLT_BACNET_MS_TP 165
+
+/*
+ * Another PPP variant as per request from Karsten Keil <kkeil@suse.de>.
+ *
+ * This is used in some OSes to allow a kernel socket filter to distinguish
+ * between incoming and outgoing packets, on a socket intended to
+ * supply pppd with outgoing packets so it can do dial-on-demand and
+ * hangup-on-lack-of-demand; incoming packets are filtered out so they
+ * don't cause pppd to hold the connection up (you don't want random
+ * input packets such as port scans, packets from old lost connections,
+ * etc. to force the connection to stay up).
+ *
+ * The first byte of the PPP header (0xff03) is modified to accomodate
+ * the direction - 0x00 = IN, 0x01 = OUT.
+ */
+#define DLT_PPP_PPPD 166
+
+/*
+ * Names for backwards compatibility with older versions of some PPP
+ * software; new software should use DLT_PPP_PPPD.
+ */
+#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD
+#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, cookies, etc..
+ */
+#define DLT_JUNIPER_PPPOE 167
+#define DLT_JUNIPER_PPPOE_ATM 168
+
+#define DLT_GPRS_LLC 169 /* GPRS LLC */
+#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */
+#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */
+
+/*
+ * Requested by Oolan Zimmer <oz@gcom.com> for use in Gcom's T1/E1 line
+ * monitoring equipment.
+ */
+#define DLT_GCOM_T1E1 172
+#define DLT_GCOM_SERIAL 173
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_ is used
+ * for internal communication to Physical Interface Cards (PIC)
+ */
+#define DLT_JUNIPER_PIC_PEER 174
+
+/*
+ * Link types requested by Gregor Maier <gregor@endace.com> of Endace
+ * Measurement Systems. They add an ERF header (see
+ * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ * the link-layer header.
+ */
+#define DLT_ERF_ETH 175 /* Ethernet */
+#define DLT_ERF_POS 176 /* Packet-over-SONET */
+
+/*
+ * Requested by Daniele Orlandi <daniele@orlandi.com> for raw LAPD
+ * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header
+ * includes additional information before the LAPD header, so it's
+ * not necessarily a generic LAPD header.
+ */
+#define DLT_LINUX_LAPD 177
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ are used for prepending meta-information
+ * like interface index, interface name
+ * before standard Ethernet, PPP, Frelay & C-HDLC Frames
+ */
+#define DLT_JUNIPER_ETHER 178
+#define DLT_JUNIPER_PPP 179
+#define DLT_JUNIPER_FRELAY 180
+#define DLT_JUNIPER_CHDLC 181
+
+/*
+ * Multi Link Frame Relay (FRF.16)
+ */
+#define DLT_MFR 182
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for internal communication with a
+ * voice Adapter Card (PIC)
+ */
+#define DLT_JUNIPER_VP 183
+
+/*
+ * Arinc 429 frames.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * Every frame contains a 32bit A429 label.
+ * More documentation on Arinc 429 can be found at
+ * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf
+ */
+#define DLT_A429 184
+
+/*
+ * Arinc 653 Interpartition Communication messages.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * Please refer to the A653-1 standard for more information.
+ */
+#define DLT_A653_ICM 185
+
+/*
+ * USB packets, beginning with a USB setup header; requested by
+ * Paolo Abeni <paolo.abeni@email.it>.
+ */
+#define DLT_USB 186
+
+/*
+ * Bluetooth HCI UART transport layer (part H:4); requested by
+ * Paolo Abeni.
+ */
+#define DLT_BLUETOOTH_HCI_H4 187
+
+/*
+ * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz
+ * <cruz_petagay@bah.com>.
+ */
+#define DLT_IEEE802_16_MAC_CPS 188
+
+/*
+ * USB packets, beginning with a Linux USB header; requested by
+ * Paolo Abeni <paolo.abeni@email.it>.
+ */
+#define DLT_USB_LINUX 189
+
+/*
+ * Controller Area Network (CAN) v. 2.0B packets.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ * Used to dump CAN packets coming from a CAN Vector board.
+ * More documentation on the CAN v2.0B frames can be found at
+ * http://www.can-cia.org/downloads/?269
+ */
+#define DLT_CAN20B 190
+
+/*
+ * IEEE 802.15.4, with address fields padded, as is done by Linux
+ * drivers; requested by Juergen Schimmer.
+ */
+#define DLT_IEEE802_15_4_LINUX 191
+
+/*
+ * Per Packet Information encapsulated packets.
+ * DLT_ requested by Gianluca Varenni <gianluca.varenni@cacetech.com>.
+ */
+#define DLT_PPI 192
+
+/*
+ * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header;
+ * requested by Charles Clancy.
+ */
+#define DLT_IEEE802_16_MAC_CPS_RADIO 193
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for internal communication with a
+ * integrated service module (ISM).
+ */
+#define DLT_JUNIPER_ISM 194
+
+/*
+ * IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ * nothing); requested by Mikko Saarnivala <mikko.saarnivala@sensinode.com>.
+ */
+#define DLT_IEEE802_15_4 195
+
+/*
+ * Various link-layer types, with a pseudo-header, for SITA
+ * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
+ */
+#define DLT_SITA 196
+
+/*
+ * Various link-layer types, with a pseudo-header, for Endace DAG cards;
+ * encapsulates Endace ERF records. Requested by Stephen Donnelly
+ * <stephen@endace.com>.
+ */
+#define DLT_ERF 197
+
+/*
+ * Special header prepended to Ethernet packets when capturing from a
+ * u10 Networks board. Requested by Phil Mulholland
+ * <phil@u10networks.com>.
+ */
+#define DLT_RAIF1 198
+
+/*
+ * IPMB packet for IPMI, beginning with the I2C slave address, followed
+ * by the netFn and LUN, etc.. Requested by Chanthy Toeung
+ * <chanthy.toeung@ca.kontron.com>.
+ */
+#define DLT_IPMB 199
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>.
+ * The DLT_ is used for capturing data on a secure tunnel interface.
+ */
+#define DLT_JUNIPER_ST 200
+
+/*
+ * Bluetooth HCI UART transport layer (part H:4), with pseudo-header
+ * that includes direction information; requested by Paolo Abeni.
+ */
+#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201
+
+/*
+ * AX.25 packet with a 1-byte KISS header; see
+ *
+ * http://www.ax25.net/kiss.htm
+ *
+ * as per Richard Stearn <richard@rns-stearn.demon.co.uk>.
+ */
+#define DLT_AX25_KISS 202
+
+/*
+ * LAPD packets from an ISDN channel, starting with the address field,
+ * with no pseudo-header.
+ * Requested by Varuna De Silva <varunax@gmail.com>.
+ */
+#define DLT_LAPD 203
+
+/*
+ * Variants of various link-layer headers, with a one-byte direction
+ * pseudo-header prepended - zero means "received by this host",
+ * non-zero (any non-zero value) means "sent by this host" - as per
+ * Will Barker <w.barker@zen.co.uk>.
+ */
+#define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */
+#define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */
+#define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */
+#define DLT_LAPB_WITH_DIR 207 /* LAPB */
+
+/*
+ * 208 is reserved for an as-yet-unspecified proprietary link-layer
+ * type, as requested by Will Barker.
+ */
+
+/*
+ * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman
+ * <avn@pigeonpoint.com>.
+ */
+#define DLT_IPMB_LINUX 209
+
+/*
+ * FlexRay automotive bus - http://www.flexray.com/ - as requested
+ * by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define DLT_FLEXRAY 210
+
+/*
+ * Media Oriented Systems Transport (MOST) bus for multimedia
+ * transport - http://www.mostcooperation.com/ - as requested
+ * by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define DLT_MOST 211
+
+/*
+ * Local Interconnect Network (LIN) bus for vehicle networks -
+ * http://www.lin-subbus.org/ - as requested by Hannes Kaelber
+ * <hannes.kaelber@x2e.de>.
+ */
+#define DLT_LIN 212
+
+/*
+ * X2E-private data link type used for serial line capture,
+ * as requested by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define DLT_X2E_SERIAL 213
+
+/*
+ * X2E-private data link type used for the Xoraya data logger
+ * family, as requested by Hannes Kaelber <hannes.kaelber@x2e.de>.
+ */
+#define DLT_X2E_XORAYA 214
+
+/*
+ * IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ * nothing), but with the PHY-level data for non-ASK PHYs (4 octets
+ * of 0 as preamble, one octet of SFD, one octet of frame length+
+ * reserved bit, and then the MAC-layer data, starting with the
+ * frame control field).
+ *
+ * Requested by Max Filippov <jcmvbkbc@gmail.com>.
+ */
+#define DLT_IEEE802_15_4_NONASK_PHY 215
+
+
+/*
+ * DLT and savefile link type values are split into a class and
+ * a member of that class. A class value of 0 indicates a regular
+ * DLT_/LINKTYPE_ value.
+ */
+#define DLT_CLASS(x) ((x) & 0x03ff0000)
+
+/*
+ * NetBSD-specific generic "raw" link type. The class value indicates
+ * that this is the generic raw type, and the lower 16 bits are the
+ * address family we're dealing with. Those values are NetBSD-specific;
+ * do not assume that they correspond to AF_ values for your operating
+ * system.
+ */
+#define DLT_CLASS_NETBSD_RAWAF 0x02240000
+#define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af))
+#define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff)
+#define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF)
+
+
+/*
+ * The instruction encodings.
+ */
+/* instruction classes */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define BPF_LD 0x00
+#define BPF_LDX 0x01
+#define BPF_ST 0x02
+#define BPF_STX 0x03
+#define BPF_ALU 0x04
+#define BPF_JMP 0x05
+#define BPF_RET 0x06
+#define BPF_MISC 0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code) ((code) & 0x18)
+#define BPF_W 0x00
+#define BPF_H 0x08
+#define BPF_B 0x10
+#define BPF_MODE(code) ((code) & 0xe0)
+#define BPF_IMM 0x00
+#define BPF_ABS 0x20
+#define BPF_IND 0x40
+#define BPF_MEM 0x60
+#define BPF_LEN 0x80
+#define BPF_MSH 0xa0
+
+/* alu/jmp fields */
+#define BPF_OP(code) ((code) & 0xf0)
+#define BPF_ADD 0x00
+#define BPF_SUB 0x10
+#define BPF_MUL 0x20
+#define BPF_DIV 0x30
+#define BPF_OR 0x40
+#define BPF_AND 0x50
+#define BPF_LSH 0x60
+#define BPF_RSH 0x70
+#define BPF_NEG 0x80
+#define BPF_JA 0x00
+#define BPF_JEQ 0x10
+#define BPF_JGT 0x20
+#define BPF_JGE 0x30
+#define BPF_JSET 0x40
+#define BPF_SRC(code) ((code) & 0x08)
+#define BPF_K 0x00
+#define BPF_X 0x08
+
+/* ret - BPF_K and BPF_X also apply */
+#define BPF_RVAL(code) ((code) & 0x18)
+#define BPF_A 0x10
+
+/* misc */
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define BPF_TAX 0x00
+#define BPF_TXA 0x80
+
+/*
+ * The instruction data structure.
+ */
+struct bpf_insn {
+ u_short code;
+ u_char jt;
+ u_char jf;
+ bpf_u_int32 k;
+};
+
+/*
+ * Macros for insn array initializers.
+ */
+#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
+#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
+
+#if __STDC__ || defined(__cplusplus)
+extern int bpf_validate(const struct bpf_insn *, int);
+extern u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
+#else
+extern int bpf_validate();
+extern u_int bpf_filter();
+#endif
+
+/*
+ * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
+ */
+#define BPF_MEMWORDS 16
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/namedb.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/namedb.h
new file mode 100644
index 000000000..9002c7509
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/namedb.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1994, 1996
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap/namedb.h,v 1.1 2006/10/04 18:09:22 guy Exp $ (LBL)
+ */
+
+#ifndef lib_pcap_namedb_h
+#define lib_pcap_namedb_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * As returned by the pcap_next_etherent()
+ * XXX this stuff doesn't belong in this interface, but this
+ * library already must do name to address translation, so
+ * on systems that don't have support for /etc/ethers, we
+ * export these hooks since they'll
+ */
+struct pcap_etherent {
+ u_char addr[6];
+ char name[122];
+};
+#ifndef PCAP_ETHERS_FILE
+#define PCAP_ETHERS_FILE "/etc/ethers"
+#endif
+struct pcap_etherent *pcap_next_etherent(FILE *);
+u_char *pcap_ether_hostton(const char*);
+u_char *pcap_ether_aton(const char *);
+
+bpf_u_int32 **pcap_nametoaddr(const char *);
+#ifdef INET6
+struct addrinfo *pcap_nametoaddrinfo(const char *);
+#endif
+bpf_u_int32 pcap_nametonetaddr(const char *);
+
+int pcap_nametoport(const char *, int *, int *);
+int pcap_nametoportrange(const char *, int *, int *, int *);
+int pcap_nametoproto(const char *);
+int pcap_nametoeproto(const char *);
+int pcap_nametollc(const char *);
+/*
+ * If a protocol is unknown, PROTO_UNDEF is returned.
+ * Also, pcap_nametoport() returns the protocol along with the port number.
+ * If there are ambiguous entried in /etc/services (i.e. domain
+ * can be either tcp or udp) PROTO_UNDEF is returned.
+ */
+#define PROTO_UNDEF -1
+
+/* XXX move these to pcap-int.h? */
+int __pcap_atodn(const char *, bpf_u_int32 *);
+int __pcap_atoin(const char *, bpf_u_int32 *);
+u_short __pcap_nametodnaddr(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/pcap.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/pcap.h
new file mode 100644
index 000000000..ad8fc40ac
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/pcap.h
@@ -0,0 +1,407 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.4.2.11 2008-10-06 15:38:39 gianluca Exp $ (LBL)
+ */
+
+#ifndef lib_pcap_pcap_h
+#define lib_pcap_pcap_h
+
+#if defined(WIN32)
+ #include <pcap-stdinc.h>
+#elif defined(MSDOS)
+ #include <sys/types.h>
+ #include <sys/socket.h> /* u_int, u_char etc. */
+#else /* UN*X */
+ #include <sys/types.h>
+ #include <sys/time.h>
+#endif /* WIN32/MSDOS/UN*X */
+
+#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H
+#include <pcap/bpf.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_REMOTE
+ // We have to define the SOCKET here, although it has been defined in sockutils.h
+ // This is to avoid the distribution of the 'sockutils.h' file around
+ // (for example in the WinPcap developer's pack)
+ #ifndef SOCKET
+ #ifdef WIN32
+ #define SOCKET unsigned int
+ #else
+ #define SOCKET int
+ #endif
+ #endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PCAP_VERSION_MAJOR 2
+#define PCAP_VERSION_MINOR 4
+
+#define PCAP_ERRBUF_SIZE 256
+
+/*
+ * Compatibility for systems that have a bpf.h that
+ * predates the bpf typedefs for 64-bit support.
+ */
+#if BPF_RELEASE - 0 < 199406
+typedef int bpf_int32;
+typedef u_int bpf_u_int32;
+#endif
+
+typedef struct pcap pcap_t;
+typedef struct pcap_dumper pcap_dumper_t;
+typedef struct pcap_if pcap_if_t;
+typedef struct pcap_addr pcap_addr_t;
+
+/*
+ * The first record in the file contains saved values for some
+ * of the flags used in the printout phases of tcpdump.
+ * Many fields here are 32 bit ints so compilers won't insert unwanted
+ * padding; these files need to be interchangeable across architectures.
+ *
+ * Do not change the layout of this structure, in any way (this includes
+ * changes that only affect the length of fields in this structure).
+ *
+ * Also, do not change the interpretation of any of the members of this
+ * structure, in any way (this includes using values other than
+ * LINKTYPE_ values, as defined in "savefile.c", in the "linktype"
+ * field).
+ *
+ * Instead:
+ *
+ * introduce a new structure for the new format, if the layout
+ * of the structure changed;
+ *
+ * send mail to "tcpdump-workers@lists.tcpdump.org", requesting
+ * a new magic number for your new capture file format, and, when
+ * you get the new magic number, put it in "savefile.c";
+ *
+ * use that magic number for save files with the changed file
+ * header;
+ *
+ * make the code in "savefile.c" capable of reading files with
+ * the old file header as well as files with the new file header
+ * (using the magic number to determine the header format).
+ *
+ * Then supply the changes as a patch at
+ *
+ * http://sourceforge.net/projects/libpcap/
+ *
+ * so that future versions of libpcap and programs that use it (such as
+ * tcpdump) will be able to read your new capture file format.
+ */
+struct pcap_file_header {
+ bpf_u_int32 magic;
+ u_short version_major;
+ u_short version_minor;
+ bpf_int32 thiszone; /* gmt to local correction */
+ bpf_u_int32 sigfigs; /* accuracy of timestamps */
+ bpf_u_int32 snaplen; /* max length saved portion of each pkt */
+ bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */
+};
+
+/*
+ * Macros for the value returned by pcap_datalink_ext().
+ *
+ * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro
+ * gives the FCS length of packets in the capture.
+ */
+#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000)
+#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28)
+#define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000)
+
+typedef enum {
+ PCAP_D_INOUT = 0,
+ PCAP_D_IN,
+ PCAP_D_OUT
+} pcap_direction_t;
+
+/*
+ * Generic per-packet information, as supplied by libpcap.
+ *
+ * The time stamp can and should be a "struct timeval", regardless of
+ * whether your system supports 32-bit tv_sec in "struct timeval",
+ * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit
+ * and 64-bit applications. The on-disk format of savefiles uses 32-bit
+ * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit
+ * and 64-bit versions of libpcap, even if they're on the same platform,
+ * should supply the appropriate version of "struct timeval", even if
+ * that's not what the underlying packet capture mechanism supplies.
+ */
+struct pcap_pkthdr {
+ struct timeval ts; /* time stamp */
+ bpf_u_int32 caplen; /* length of portion present */
+ bpf_u_int32 len; /* length this packet (off wire) */
+};
+
+/*
+ * As returned by the pcap_stats()
+ */
+struct pcap_stat {
+ u_int ps_recv; /* number of packets received */
+ u_int ps_drop; /* number of packets dropped */
+ u_int ps_ifdrop; /* drops by interface XXX not yet supported */
+#ifdef HAVE_REMOTE
+ u_int ps_capt; /* number of packets that are received by the application; please get rid off the Win32 ifdef */
+ u_int ps_sent; /* number of packets sent by the server on the network */
+ u_int ps_netdrop; /* number of packets lost on the network */
+#endif /* HAVE_REMOTE */
+};
+
+#ifdef MSDOS
+/*
+ * As returned by the pcap_stats_ex()
+ */
+struct pcap_stat_ex {
+ u_long rx_packets; /* total packets received */
+ u_long tx_packets; /* total packets transmitted */
+ u_long rx_bytes; /* total bytes received */
+ u_long tx_bytes; /* total bytes transmitted */
+ u_long rx_errors; /* bad packets received */
+ u_long tx_errors; /* packet transmit problems */
+ u_long rx_dropped; /* no space in Rx buffers */
+ u_long tx_dropped; /* no space available for Tx */
+ u_long multicast; /* multicast packets received */
+ u_long collisions;
+
+ /* detailed rx_errors: */
+ u_long rx_length_errors;
+ u_long rx_over_errors; /* receiver ring buff overflow */
+ u_long rx_crc_errors; /* recv'd pkt with crc error */
+ u_long rx_frame_errors; /* recv'd frame alignment error */
+ u_long rx_fifo_errors; /* recv'r fifo overrun */
+ u_long rx_missed_errors; /* recv'r missed packet */
+
+ /* detailed tx_errors */
+ u_long tx_aborted_errors;
+ u_long tx_carrier_errors;
+ u_long tx_fifo_errors;
+ u_long tx_heartbeat_errors;
+ u_long tx_window_errors;
+ };
+#endif
+
+/*
+ * Item in a list of interfaces.
+ */
+struct pcap_if {
+ struct pcap_if *next;
+ char *name; /* name to hand to "pcap_open_live()" */
+ char *description; /* textual description of interface, or NULL */
+ struct pcap_addr *addresses;
+ bpf_u_int32 flags; /* PCAP_IF_ interface flags */
+};
+
+#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */
+
+/*
+ * Representation of an interface address.
+ */
+struct pcap_addr {
+ struct pcap_addr *next;
+ struct sockaddr *addr; /* address */
+ struct sockaddr *netmask; /* netmask for that address */
+ struct sockaddr *broadaddr; /* broadcast address for that address */
+ struct sockaddr *dstaddr; /* P2P destination address for that address */
+};
+
+typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
+ const u_char *);
+
+/*
+ * Error codes for the pcap API.
+ * These will all be negative, so you can check for the success or
+ * failure of a call that returns these codes by checking for a
+ * negative value.
+ */
+#define PCAP_ERROR -1 /* generic error code */
+#define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */
+#define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */
+#define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */
+#define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */
+#define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */
+#define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */
+#define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */
+#define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */
+
+/*
+ * Warning codes for the pcap API.
+ * These will all be positive and non-zero, so they won't look like
+ * errors.
+ */
+#define PCAP_WARNING 1 /* generic warning code */
+#define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */
+
+char *pcap_lookupdev(char *);
+int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *);
+
+pcap_t *pcap_create(const char *, char *);
+int pcap_set_snaplen(pcap_t *, int);
+int pcap_set_promisc(pcap_t *, int);
+int pcap_can_set_rfmon(pcap_t *);
+int pcap_set_rfmon(pcap_t *, int);
+int pcap_set_timeout(pcap_t *, int);
+int pcap_set_buffer_size(pcap_t *, int);
+int pcap_activate(pcap_t *);
+
+pcap_t *pcap_open_live(const char *, int, int, int, char *);
+pcap_t *pcap_open_dead(int, int);
+pcap_t *pcap_open_offline(const char *, char *);
+#if defined(WIN32)
+pcap_t *pcap_hopen_offline(intptr_t, char *);
+#if !defined(LIBPCAP_EXPORTS)
+#define pcap_fopen_offline(f,b) \
+ pcap_hopen_offline(_get_osfhandle(_fileno(f)), b)
+#else /*LIBPCAP_EXPORTS*/
+static pcap_t *pcap_fopen_offline(FILE *, char *);
+#endif
+#else /*WIN32*/
+pcap_t *pcap_fopen_offline(FILE *, char *);
+#endif /*WIN32*/
+
+void pcap_close(pcap_t *);
+int pcap_loop(pcap_t *, int, pcap_handler, u_char *);
+int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *);
+const u_char*
+ pcap_next(pcap_t *, struct pcap_pkthdr *);
+int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **);
+void pcap_breakloop(pcap_t *);
+int pcap_stats(pcap_t *, struct pcap_stat *);
+int pcap_setfilter(pcap_t *, struct bpf_program *);
+int pcap_setdirection(pcap_t *, pcap_direction_t);
+int pcap_getnonblock(pcap_t *, char *);
+int pcap_setnonblock(pcap_t *, int, char *);
+int pcap_inject(pcap_t *, const void *, size_t);
+int pcap_sendpacket(pcap_t *, const u_char *, int);
+const char *pcap_statustostr(int);
+const char *pcap_strerror(int);
+char *pcap_geterr(pcap_t *);
+void pcap_perror(pcap_t *, char *);
+int pcap_compile(pcap_t *, struct bpf_program *, const char *, int,
+ bpf_u_int32);
+int pcap_compile_nopcap(int, int, struct bpf_program *,
+ const char *, int, bpf_u_int32);
+void pcap_freecode(struct bpf_program *);
+int pcap_offline_filter(struct bpf_program *, const struct pcap_pkthdr *,
+ const u_char *);
+int pcap_datalink(pcap_t *);
+int pcap_datalink_ext(pcap_t *);
+int pcap_list_datalinks(pcap_t *, int **);
+int pcap_set_datalink(pcap_t *, int);
+void pcap_free_datalinks(int *);
+int pcap_datalink_name_to_val(const char *);
+const char *pcap_datalink_val_to_name(int);
+const char *pcap_datalink_val_to_description(int);
+int pcap_snapshot(pcap_t *);
+int pcap_is_swapped(pcap_t *);
+int pcap_major_version(pcap_t *);
+int pcap_minor_version(pcap_t *);
+
+/* XXX */
+FILE *pcap_file(pcap_t *);
+int pcap_fileno(pcap_t *);
+
+pcap_dumper_t *pcap_dump_open(pcap_t *, const char *);
+pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp);
+FILE *pcap_dump_file(pcap_dumper_t *);
+long pcap_dump_ftell(pcap_dumper_t *);
+int pcap_dump_flush(pcap_dumper_t *);
+void pcap_dump_close(pcap_dumper_t *);
+void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *);
+
+int pcap_findalldevs(pcap_if_t **, char *);
+void pcap_freealldevs(pcap_if_t *);
+
+const char *pcap_lib_version(void);
+
+/* XXX this guy lives in the bpf tree */
+u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
+int bpf_validate(const struct bpf_insn *f, int len);
+char *bpf_image(const struct bpf_insn *, int);
+void bpf_dump(const struct bpf_program *, int);
+
+#if defined(WIN32)
+
+/*
+ * Win32 definitions
+ */
+
+int pcap_setbuff(pcap_t *p, int dim);
+int pcap_setmode(pcap_t *p, int mode);
+int pcap_setmintocopy(pcap_t *p, int size);
+
+#ifdef WPCAP
+/* Include file with the wpcap-specific extensions */
+#include <Win32-Extensions.h>
+#endif /* WPCAP */
+
+#define MODE_CAPT 0
+#define MODE_STAT 1
+#define MODE_MON 2
+
+#elif defined(MSDOS)
+
+/*
+ * MS-DOS definitions
+ */
+
+int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *);
+void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait);
+u_long pcap_mac_packets (void);
+
+#else /* UN*X */
+
+/*
+ * UN*X definitions
+ */
+
+int pcap_get_selectable_fd(pcap_t *);
+
+#endif /* WIN32/MSDOS/UN*X */
+
+#ifdef HAVE_REMOTE
+/* Includes most of the public stuff that is needed for the remote capture */
+#include <remote-ext.h>
+#endif /* HAVE_REMOTE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/sll.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/sll.h
new file mode 100644
index 000000000..e9d5452af
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/sll.h
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap/sll.h,v 1.2.2.1 2008-05-30 01:36:06 guy Exp $ (LBL)
+ */
+
+/*
+ * For captures on Linux cooked sockets, we construct a fake header
+ * that includes:
+ *
+ * a 2-byte "packet type" which is one of:
+ *
+ * LINUX_SLL_HOST packet was sent to us
+ * LINUX_SLL_BROADCAST packet was broadcast
+ * LINUX_SLL_MULTICAST packet was multicast
+ * LINUX_SLL_OTHERHOST packet was sent to somebody else
+ * LINUX_SLL_OUTGOING packet was sent *by* us;
+ *
+ * a 2-byte Ethernet protocol field;
+ *
+ * a 2-byte link-layer type;
+ *
+ * a 2-byte link-layer address length;
+ *
+ * an 8-byte source link-layer address, whose actual length is
+ * specified by the previous value.
+ *
+ * All fields except for the link-layer address are in network byte order.
+ *
+ * DO NOT change the layout of this structure, or change any of the
+ * LINUX_SLL_ values below. If you must change the link-layer header
+ * for a "cooked" Linux capture, introduce a new DLT_ type (ask
+ * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it
+ * a value that collides with a value already being used), and use the
+ * new header in captures of that type, so that programs that can
+ * handle DLT_LINUX_SLL captures will continue to handle them correctly
+ * without any change, and so that capture files with different headers
+ * can be told apart and programs that read them can dissect the
+ * packets in them.
+ */
+
+#ifndef lib_pcap_sll_h
+#define lib_pcap_sll_h
+
+/*
+ * A DLT_LINUX_SLL fake link-layer header.
+ */
+#define SLL_HDR_LEN 16 /* total header length */
+#define SLL_ADDRLEN 8 /* length of address field */
+
+struct sll_header {
+ u_int16_t sll_pkttype; /* packet type */
+ u_int16_t sll_hatype; /* link-layer address type */
+ u_int16_t sll_halen; /* link-layer address length */
+ u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */
+ u_int16_t sll_protocol; /* protocol */
+};
+
+/*
+ * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the
+ * PACKET_ values on Linux, but are defined here so that they're
+ * available even on systems other than Linux, and so that they
+ * don't change even if the PACKET_ values change.
+ */
+#define LINUX_SLL_HOST 0
+#define LINUX_SLL_BROADCAST 1
+#define LINUX_SLL_MULTICAST 2
+#define LINUX_SLL_OTHERHOST 3
+#define LINUX_SLL_OUTGOING 4
+
+/*
+ * The LINUX_SLL_ values for "sll_protocol"; these correspond to the
+ * ETH_P_ values on Linux, but are defined here so that they're
+ * available even on systems other than Linux. We assume, for now,
+ * that the ETH_P_ values won't change in Linux; if they do, then:
+ *
+ * if we don't translate them in "pcap-linux.c", capture files
+ * won't necessarily be readable if captured on a system that
+ * defines ETH_P_ values that don't match these values;
+ *
+ * if we do translate them in "pcap-linux.c", that makes life
+ * unpleasant for the BPF code generator, as the values you test
+ * for in the kernel aren't the values that you test for when
+ * reading a capture file, so the fixup code run on BPF programs
+ * handed to the kernel ends up having to do more work.
+ *
+ * Add other values here as necessary, for handling packet types that
+ * might show up on non-Ethernet, non-802.x networks. (Not all the ones
+ * in the Linux "if_ether.h" will, I suspect, actually show up in
+ * captures.)
+ */
+#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */
+#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */
+
+#endif
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/usb.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/usb.h
new file mode 100644
index 000000000..adcd19c05
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/usb.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2006 Paolo Abeni (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Basic USB data struct
+ * By Paolo Abeni <paolo.abeni@email.it>
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap/usb.h,v 1.6 2007/09/22 02:06:08 guy Exp $
+ */
+
+#ifndef _PCAP_USB_STRUCTS_H__
+#define _PCAP_USB_STRUCTS_H__
+
+/*
+ * possible transfer mode
+ */
+#define URB_TRANSFER_IN 0x80
+#define URB_ISOCHRONOUS 0x0
+#define URB_INTERRUPT 0x1
+#define URB_CONTROL 0x2
+#define URB_BULK 0x3
+
+/*
+ * possible event type
+ */
+#define URB_SUBMIT 'S'
+#define URB_COMPLETE 'C'
+#define URB_ERROR 'E'
+
+/*
+ * USB setup header as defined in USB specification.
+ * Appears at the front of each packet in DLT_USB captures.
+ */
+typedef struct _usb_setup {
+ u_int8_t bmRequestType;
+ u_int8_t bRequest;
+ u_int16_t wValue;
+ u_int16_t wIndex;
+ u_int16_t wLength;
+} pcap_usb_setup;
+
+
+/*
+ * Header prepended by linux kernel to each event.
+ * Appears at the front of each packet in DLT_USB_LINUX captures.
+ */
+typedef struct _usb_header {
+ u_int64_t id;
+ u_int8_t event_type;
+ u_int8_t transfer_type;
+ u_int8_t endpoint_number;
+ u_int8_t device_address;
+ u_int16_t bus_id;
+ char setup_flag;/*if !=0 the urb setup header is not present*/
+ char data_flag; /*if !=0 no urb data is present*/
+ int64_t ts_sec;
+ int32_t ts_usec;
+ int32_t status;
+ u_int32_t urb_len;
+ u_int32_t data_len; /* amount of urb data really present in this event*/
+ pcap_usb_setup setup;
+} pcap_usb_header;
+
+
+#endif
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/vlan.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/vlan.h
new file mode 100644
index 000000000..b0cb7949b
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/pcap/vlan.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap/vlan.h,v 1.1.2.2 2008-08-06 07:45:59 guy Exp $
+ */
+
+#ifndef lib_pcap_vlan_h
+#define lib_pcap_vlan_h
+
+struct vlan_tag {
+ u_int16_t vlan_tpid; /* ETH_P_8021Q */
+ u_int16_t vlan_tci; /* VLAN TCI */
+};
+
+#define VLAN_TAG_LEN 4
+
+#endif
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/remote-ext.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/remote-ext.h
new file mode 100644
index 000000000..9f54d6974
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/remote-ext.h
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2002 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef __REMOTE_EXT_H__
+#define __REMOTE_EXT_H__
+
+
+#ifndef HAVE_REMOTE
+#error Please do not include this file directly. Just define HAVE_REMOTE and then include pcap.h
+#endif
+
+// Definition for Microsoft Visual Studio
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ \file remote-ext.h
+
+ The goal of this file it to include most of the new definitions that should be
+ placed into the pcap.h file.
+
+ It includes all new definitions (structures and functions like pcap_open().
+ Some of the functions are not really a remote feature, but, right now,
+ they are placed here.
+*/
+
+
+
+// All this stuff is public
+/*! \addtogroup remote_struct
+ \{
+*/
+
+
+
+
+/*!
+ \brief Defines the maximum buffer size in which address, port, interface names are kept.
+
+ In case the adapter name or such is larger than this value, it is truncated.
+ This is not used by the user; however it must be aware that an hostname / interface
+ name longer than this value will be truncated.
+*/
+#define PCAP_BUF_SIZE 1024
+
+
+/*! \addtogroup remote_source_ID
+ \{
+*/
+
+
+/*!
+ \brief Internal representation of the type of source in use (file,
+ remote/local interface).
+
+ This indicates a file, i.e. the user want to open a capture from a local file.
+*/
+#define PCAP_SRC_FILE 2
+/*!
+ \brief Internal representation of the type of source in use (file,
+ remote/local interface).
+
+ This indicates a local interface, i.e. the user want to open a capture from
+ a local interface. This does not involve the RPCAP protocol.
+*/
+#define PCAP_SRC_IFLOCAL 3
+/*!
+ \brief Internal representation of the type of source in use (file,
+ remote/local interface).
+
+ This indicates a remote interface, i.e. the user want to open a capture from
+ an interface on a remote host. This does involve the RPCAP protocol.
+*/
+#define PCAP_SRC_IFREMOTE 4
+
+/*!
+ \}
+*/
+
+
+
+/*! \addtogroup remote_source_string
+
+ The formats allowed by the pcap_open() are the following:
+ - file://path_and_filename [opens a local file]
+ - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol]
+ - rpcap://host/devicename [opens the selected device available on a remote host]
+ - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP]
+ - adaptername [to open a local adapter; kept for compability, but it is strongly discouraged]
+ - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged]
+
+ The formats allowed by the pcap_findalldevs_ex() are the following:
+ - file://folder/ [lists all the files in the given folder]
+ - rpcap:// [lists all local adapters]
+ - rpcap://host:port/ [lists the devices available on a remote host]
+
+ Referring to the 'host' and 'port' paramters, they can be either numeric or literal. Since
+ IPv6 is fully supported, these are the allowed formats:
+
+ - host (literal): e.g. host.foo.bar
+ - host (numeric IPv4): e.g. 10.11.12.13
+ - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13]
+ - host (numeric IPv6): e.g. [1:2:3::4]
+ - port: can be either numeric (e.g. '80') or literal (e.g. 'http')
+
+ Here you find some allowed examples:
+ - rpcap://host.foo.bar/devicename [everything literal, no port number]
+ - rpcap://host.foo.bar:1234/devicename [everything literal, with port number]
+ - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number]
+ - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number]
+ - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number]
+ - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number]
+ - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number]
+ - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number]
+
+ \{
+*/
+
+
+/*!
+ \brief String that will be used to determine the type of source in use (file,
+ remote/local interface).
+
+ This string will be prepended to the interface name in order to create a string
+ that contains all the information required to open the source.
+
+ This string indicates that the user wants to open a capture from a local file.
+*/
+#define PCAP_SRC_FILE_STRING "file://"
+/*!
+ \brief String that will be used to determine the type of source in use (file,
+ remote/local interface).
+
+ This string will be prepended to the interface name in order to create a string
+ that contains all the information required to open the source.
+
+ This string indicates that the user wants to open a capture from a network interface.
+ This string does not necessarily involve the use of the RPCAP protocol. If the
+ interface required resides on the local host, the RPCAP protocol is not involved
+ and the local functions are used.
+*/
+#define PCAP_SRC_IF_STRING "rpcap://"
+
+/*!
+ \}
+*/
+
+
+
+
+
+/*!
+ \addtogroup remote_open_flags
+ \{
+*/
+
+/*!
+ \brief Defines if the adapter has to go in promiscuous mode.
+
+ It is '1' if you have to open the adapter in promiscuous mode, '0' otherwise.
+ Note that even if this parameter is false, the interface could well be in promiscuous
+ mode for some other reason (for example because another capture process with
+ promiscuous mode enabled is currently using that interface).
+ On on Linux systems with 2.2 or later kernels (that have the "any" device), this
+ flag does not work on the "any" device; if an argument of "any" is supplied,
+ the 'promisc' flag is ignored.
+*/
+#define PCAP_OPENFLAG_PROMISCUOUS 1
+
+/*!
+ \brief Defines if the data trasfer (in case of a remote
+ capture) has to be done with UDP protocol.
+
+ If it is '1' if you want a UDP data connection, '0' if you want
+ a TCP data connection; control connection is always TCP-based.
+ A UDP connection is much lighter, but it does not guarantee that all
+ the captured packets arrive to the client workstation. Moreover,
+ it could be harmful in case of network congestion.
+ This flag is meaningless if the source is not a remote interface.
+ In that case, it is simply ignored.
+*/
+#define PCAP_OPENFLAG_DATATX_UDP 2
+
+
+/*!
+ \brief Defines if the remote probe will capture its own generated traffic.
+
+ In case the remote probe uses the same interface to capture traffic and to send
+ data back to the caller, the captured traffic includes the RPCAP traffic as well.
+ If this flag is turned on, the RPCAP traffic is excluded from the capture, so that
+ the trace returned back to the collector is does not include this traffic.
+*/
+#define PCAP_OPENFLAG_NOCAPTURE_RPCAP 4
+
+/*!
+ \brief Defines if the local adapter will capture its own generated traffic.
+
+ This flag tells the underlying capture driver to drop the packets that were sent by itself.
+ This is usefult when building applications like bridges, that should ignore the traffic
+ they just sent.
+*/
+#define PCAP_OPENFLAG_NOCAPTURE_LOCAL 8
+
+/*!
+ \brief This flag configures the adapter for maximum responsiveness.
+
+ In presence of a large value for nbytes, WinPcap waits for the arrival of several packets before
+ copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage,
+ i.e. better performance, which is good for applications like sniffers. If the user sets the
+ PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will copy the packets as soon as the application
+ is ready to receive them. This is suggested for real time applications (like, for example, a bridge)
+ that need the best responsiveness.*/
+#define PCAP_OPENFLAG_MAX_RESPONSIVENESS 16
+
+/*!
+ \}
+*/
+
+
+/*!
+ \addtogroup remote_samp_methods
+ \{
+*/
+
+/*!
+ \brief No sampling has to be done on the current capture.
+
+ In this case, no sampling algorithms are applied to the current capture.
+*/
+#define PCAP_SAMP_NOSAMP 0
+
+/*!
+ \brief It defines that only 1 out of N packets must be returned to the user.
+
+ In this case, the 'value' field of the 'pcap_samp' structure indicates the
+ number of packets (minus 1) that must be discarded before one packet got accepted.
+ In other words, if 'value = 10', the first packet is returned to the caller, while
+ the following 9 are discarded.
+*/
+#define PCAP_SAMP_1_EVERY_N 1
+
+/*!
+ \brief It defines that we have to return 1 packet every N milliseconds.
+
+ In this case, the 'value' field of the 'pcap_samp' structure indicates the 'waiting
+ time' in milliseconds before one packet got accepted.
+ In other words, if 'value = 10', the first packet is returned to the caller; the next
+ returned one will be the first packet that arrives when 10ms have elapsed.
+*/
+#define PCAP_SAMP_FIRST_AFTER_N_MS 2
+
+/*!
+ \}
+*/
+
+
+/*!
+ \addtogroup remote_auth_methods
+ \{
+*/
+
+/*!
+ \brief It defines the NULL authentication.
+
+ This value has to be used within the 'type' member of the pcap_rmtauth structure.
+ The 'NULL' authentication has to be equal to 'zero', so that old applications
+ can just put every field of struct pcap_rmtauth to zero, and it does work.
+*/
+#define RPCAP_RMTAUTH_NULL 0
+/*!
+ \brief It defines the username/password authentication.
+
+ With this type of authentication, the RPCAP protocol will use the username/
+ password provided to authenticate the user on the remote machine. If the
+ authentication is successful (and the user has the right to open network devices)
+ the RPCAP connection will continue; otherwise it will be dropped.
+
+ This value has to be used within the 'type' member of the pcap_rmtauth structure.
+*/
+#define RPCAP_RMTAUTH_PWD 1
+
+/*!
+ \}
+*/
+
+
+
+
+/*!
+
+ \brief This structure keeps the information needed to autheticate
+ the user on a remote machine.
+
+ The remote machine can either grant or refuse the access according
+ to the information provided.
+ In case the NULL authentication is required, both 'username' and
+ 'password' can be NULL pointers.
+
+ This structure is meaningless if the source is not a remote interface;
+ in that case, the functions which requires such a structure can accept
+ a NULL pointer as well.
+*/
+struct pcap_rmtauth
+{
+ /*!
+ \brief Type of the authentication required.
+
+ In order to provide maximum flexibility, we can support different types
+ of authentication based on the value of this 'type' variable. The currently
+ supported authentication methods are defined into the
+ \link remote_auth_methods Remote Authentication Methods Section\endlink.
+
+ */
+ int type;
+ /*!
+ \brief Zero-terminated string containing the username that has to be
+ used on the remote machine for authentication.
+
+ This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication
+ and it can be NULL.
+ */
+ char *username;
+ /*!
+ \brief Zero-terminated string containing the password that has to be
+ used on the remote machine for authentication.
+
+ This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication
+ and it can be NULL.
+ */
+ char *password;
+};
+
+
+/*!
+ \brief This structure defines the information related to sampling.
+
+ In case the sampling is requested, the capturing device should read
+ only a subset of the packets coming from the source. The returned packets depend
+ on the sampling parameters.
+
+ \warning The sampling process is applied <strong>after</strong> the filtering process.
+ In other words, packets are filtered first, then the sampling process selects a
+ subset of the 'filtered' packets and it returns them to the caller.
+*/
+struct pcap_samp
+{
+ /*!
+ Method used for sampling. Currently, the supported methods are listed in the
+ \link remote_samp_methods Sampling Methods Section\endlink.
+ */
+ int method;
+
+ /*!
+ This value depends on the sampling method defined. For its meaning, please check
+ at the \link remote_samp_methods Sampling Methods Section\endlink.
+ */
+ int value;
+};
+
+
+
+
+//! Maximum lenght of an host name (needed for the RPCAP active mode)
+#define RPCAP_HOSTLIST_SIZE 1024
+
+
+/*!
+ \}
+*/ // end of public documentation
+
+
+// Exported functions
+
+
+
+/** \name New WinPcap functions
+
+ This section lists the new functions that are able to help considerably in writing
+ WinPcap programs because of their easiness of use.
+ */
+//\{
+pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf);
+int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf);
+int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf);
+int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf);
+struct pcap_samp *pcap_setsampling(pcap_t *p);
+
+//\}
+// End of new winpcap functions
+
+
+
+/** \name Remote Capture functions
+ */
+//\{
+SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf);
+int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf);
+int pcap_remoteact_close(const char *host, char *errbuf);
+void pcap_remoteact_cleanup();
+//\}
+// End of remote capture functions
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/wpcap.lib b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/wpcap.lib
new file mode 100644
index 000000000..f832e0445
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/WinPCap/wpcap.lib
Binary files differ
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/demo_logging.c b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/demo_logging.c
new file mode 100644
index 000000000..6646fc79f
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/demo_logging.c
@@ -0,0 +1,568 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * Logging utility that allows FreeRTOS tasks to log to a UDP port, stdout, and
+ * disk file without making any Win32 system calls themselves.
+ *
+ * Messages logged to a UDP port are sent directly (using FreeRTOS+TCP), but as
+ * FreeRTOS tasks cannot make Win32 system calls messages sent to stdout or a
+ * disk file are sent via a stream buffer to a Win32 thread which then performs
+ * the actual output.
+ */
+
+/* Standard includes. */
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <io.h>
+#include <ctype.h>
+
+/* FreeRTOS includes. */
+#include <FreeRTOS.h>
+#include "task.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_Stream_Buffer.h"
+
+/* Demo includes. */
+#include "demo_logging.h"
+
+/*-----------------------------------------------------------*/
+
+/* The maximum size to which the log file may grow, before being renamed
+to .ful. */
+#define dlLOGGING_FILE_SIZE ( 40ul * 1024ul * 1024ul )
+
+/* Dimensions the arrays into which print messages are created. */
+#define dlMAX_PRINT_STRING_LENGTH 255
+
+/* The size of the stream buffer used to pass messages from FreeRTOS tasks to
+the Win32 thread that is responsible for making any Win32 system calls that are
+necessary for the selected logging method. */
+#define dlLOGGING_STREAM_BUFFER_SIZE 32768
+
+/* A block time of zero simply means don't block. */
+#define dlDONT_BLOCK 0
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Called from vLoggingInit() to start a new disk log file.
+ */
+static void prvFileLoggingInit( void );
+
+/*
+ * Attempt to write a message to the file.
+ */
+static void prvLogToFile( const char *pcMessage, size_t xLength );
+
+/*
+ * Simply close the logging file, if it is open.
+ */
+static void prvFileClose( void );
+
+/*
+ * Before the scheduler is started this function is called directly. After the
+ * scheduler has started it is called from the Windows thread dedicated to
+ * outputting log messages. Only the windows thread actually performs the
+ * writing so as not to disrupt the simulation by making Windows system calls
+ * from FreeRTOS tasks.
+ */
+static void prvLoggingFlushBuffer( void );
+
+/*
+ * The windows thread that performs the actual writing of messages that require
+ * Win32 system calls. Only the windows thread can make system calls so as not
+ * to disrupt the simulation by making Windows calls from FreeRTOS tasks.
+ */
+static DWORD WINAPI prvWin32LoggingThread( void *pvParam );
+
+/*
+ * Creates the socket to which UDP messages are sent. This function is not
+ * called directly to prevent the print socket being created from within the IP
+ * task - which could result in a deadlock. Instead the function call is
+ * deferred to run in the RTOS daemon task - hence it prototype.
+ */
+static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 );
+
+/*-----------------------------------------------------------*/
+
+/* Windows event used to wake the Win32 thread which performs any logging that
+needs Win32 system calls. */
+static void *pvLoggingThreadEvent = NULL;
+
+/* Stores the selected logging targets passed in as parameters to the
+vLoggingInit() function. */
+BaseType_t xStdoutLoggingUsed = pdFALSE, xDiskFileLoggingUsed = pdFALSE, xUDPLoggingUsed = pdFALSE;
+
+/* Circular buffer used to pass messages from the FreeRTOS tasks to the Win32
+thread that is responsible for making Win32 calls (when stdout or a disk log is
+used). */
+static StreamBuffer_t *xLogStreamBuffer = NULL;
+
+/* Handle to the file used for logging. This is left open while there are
+messages waiting to be logged, then closed again in between logs. */
+static FILE *pxLoggingFileHandle = NULL;
+
+/* When true prints are performed directly. After start up xDirectPrint is set
+to pdFALSE - at which time prints that require Win32 system calls are done by
+the Win32 thread responsible for logging. */
+BaseType_t xDirectPrint = pdTRUE;
+
+/* File names for the in use and complete (full) log files. */
+static const char *pcLogFileName = "RTOSDemo.log";
+static const char *pcFullLogFileName = "RTOSDemo.ful";
+
+/* Keep the current file size in a variable, as an optimisation. */
+static size_t ulSizeOfLoggingFile = 0ul;
+
+/* The UDP socket and address on/to which print messages are sent. */
+Socket_t xPrintSocket = FREERTOS_INVALID_SOCKET;
+struct freertos_sockaddr xPrintUDPAddress;
+
+/*-----------------------------------------------------------*/
+
+void vLoggingInit( BaseType_t xLogToStdout, BaseType_t xLogToFile, BaseType_t xLogToUDP, uint32_t ulRemoteIPAddress, uint16_t usRemotePort )
+{
+ /* Can only be called before the scheduler has started. */
+ configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED );
+
+ #if( ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) )
+ {
+ HANDLE Win32Thread;
+
+ /* Record which output methods are to be used. */
+ xStdoutLoggingUsed = xLogToStdout;
+ xDiskFileLoggingUsed = xLogToFile;
+ xUDPLoggingUsed = xLogToUDP;
+
+ /* If a disk file is used then initialise it now. */
+ if( xDiskFileLoggingUsed != pdFALSE )
+ {
+ prvFileLoggingInit();
+ }
+
+ /* If UDP logging is used then store the address to which the log data
+ will be sent - but don't create the socket yet because the network is
+ not initialised. */
+ if( xUDPLoggingUsed != pdFALSE )
+ {
+ /* Set the address to which the print messages are sent. */
+ xPrintUDPAddress.sin_port = FreeRTOS_htons( usRemotePort );
+ xPrintUDPAddress.sin_addr = ulRemoteIPAddress;
+ }
+
+ /* If a disk file or stdout are to be used then Win32 system calls will
+ have to be made. Such system calls cannot be made from FreeRTOS tasks
+ so create a stream buffer to pass the messages to a Win32 thread, then
+ create the thread itself, along with a Win32 event that can be used to
+ unblock the thread. */
+ if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) )
+ {
+ /* Create the buffer. */
+ xLogStreamBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) + dlLOGGING_STREAM_BUFFER_SIZE + 1 );
+ configASSERT( xLogStreamBuffer );
+ memset( xLogStreamBuffer, '\0', sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) );
+ xLogStreamBuffer->LENGTH = dlLOGGING_STREAM_BUFFER_SIZE + 1;
+
+ /* Create the Windows event. */
+ pvLoggingThreadEvent = CreateEvent( NULL, FALSE, TRUE, "StdoutLoggingEvent" );
+
+ /* Create the thread itself. */
+ Win32Thread = CreateThread(
+ NULL, /* Pointer to thread security attributes. */
+ 0, /* Initial thread stack size, in bytes. */
+ prvWin32LoggingThread, /* Pointer to thread function. */
+ NULL, /* Argument for new thread. */
+ 0, /* Creation flags. */
+ NULL );
+
+ /* Use the cores that are not used by the FreeRTOS tasks. */
+ SetThreadAffinityMask( Win32Thread, ~0x01u );
+ SetThreadPriorityBoost( Win32Thread, TRUE );
+ SetThreadPriority( Win32Thread, THREAD_PRIORITY_IDLE );
+ }
+ }
+ #else
+ {
+ /* FreeRTOSIPConfig is set such that no print messages will be output.
+ Avoid compiler warnings about unused parameters. */
+ ( void ) xLogToStdout;
+ ( void ) xLogToFile;
+ ( void ) xLogToUDP;
+ ( void ) usRemotePort;
+ ( void ) ulRemoteIPAddress;
+ }
+ #endif /* ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) */
+}
+/*-----------------------------------------------------------*/
+
+static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 )
+{
+static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 0 );
+Socket_t xSocket;
+
+ /* The function prototype is that of a deferred function, but the parameters
+ are not actually used. */
+ ( void ) pvParameter1;
+ ( void ) ulParameter2;
+
+ xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
+
+ if( xSocket != FREERTOS_INVALID_SOCKET )
+ {
+ /* FreeRTOS+TCP decides which port to bind to. */
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) );
+ FreeRTOS_bind( xSocket, NULL, 0 );
+
+ /* Now the socket is bound it can be assigned to the print socket. */
+ xPrintSocket = xSocket;
+ }
+}
+/*-----------------------------------------------------------*/
+
+void vLoggingPrintf( const char *pcFormat, ... )
+{
+char cPrintString[ dlMAX_PRINT_STRING_LENGTH ];
+char cOutputString[ dlMAX_PRINT_STRING_LENGTH ];
+char *pcSource, *pcTarget, *pcBegin;
+size_t xLength, xLength2, rc;
+static BaseType_t xMessageNumber = 0;
+va_list args;
+uint32_t ulIPAddress;
+const char *pcTaskName;
+const char *pcNoTask = "None";
+int iOriginalPriority;
+HANDLE xCurrentTask;
+
+
+ if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) || ( xUDPLoggingUsed != pdFALSE ) )
+ {
+ /* There are a variable number of parameters. */
+ va_start( args, pcFormat );
+
+ /* Additional info to place at the start of the log. */
+ if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED )
+ {
+ pcTaskName = pcTaskGetName( NULL );
+ }
+ else
+ {
+ pcTaskName = pcNoTask;
+ }
+
+ if( strcmp( pcFormat, "\n" ) != 0 )
+ {
+ xLength = snprintf( cPrintString, dlMAX_PRINT_STRING_LENGTH, "%lu %lu [%s] ",
+ xMessageNumber++,
+ ( unsigned long ) xTaskGetTickCount(),
+ pcTaskName );
+ }
+ else
+ {
+ xLength = 0;
+ memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH );
+ }
+
+ xLength2 = vsnprintf( cPrintString + xLength, dlMAX_PRINT_STRING_LENGTH - xLength, pcFormat, args );
+
+ if( xLength2 < 0 )
+ {
+ /* Clean up. */
+ xLength2 = sizeof( cPrintString ) - 1 - xLength;
+ cPrintString[ sizeof( cPrintString ) - 1 ] = '\0';
+ }
+
+ xLength += xLength2;
+ va_end( args );
+
+ /* For ease of viewing, copy the string into another buffer, converting
+ IP addresses to dot notation on the way. */
+ pcSource = cPrintString;
+ pcTarget = cOutputString;
+
+ while( ( *pcSource ) != '\0' )
+ {
+ *pcTarget = *pcSource;
+ pcTarget++;
+ pcSource++;
+
+ /* Look forward for an IP address denoted by 'ip'. */
+ if( ( isxdigit( pcSource[ 0 ] ) != pdFALSE ) && ( pcSource[ 1 ] == 'i' ) && ( pcSource[ 2 ] == 'p' ) )
+ {
+ *pcTarget = *pcSource;
+ pcTarget++;
+ *pcTarget = '\0';
+ pcBegin = pcTarget - 8;
+
+ while( ( pcTarget > pcBegin ) && ( isxdigit( pcTarget[ -1 ] ) != pdFALSE ) )
+ {
+ pcTarget--;
+ }
+
+ sscanf( pcTarget, "%8X", &ulIPAddress );
+ rc = sprintf( pcTarget, "%lu.%lu.%lu.%lu",
+ ( unsigned long ) ( ulIPAddress >> 24UL ),
+ ( unsigned long ) ( (ulIPAddress >> 16UL) & 0xffUL ),
+ ( unsigned long ) ( (ulIPAddress >> 8UL) & 0xffUL ),
+ ( unsigned long ) ( ulIPAddress & 0xffUL ) );
+ pcTarget += rc;
+ pcSource += 3; /* skip "<n>ip" */
+ }
+ }
+
+ /* How far through the buffer was written? */
+ xLength = ( BaseType_t ) ( pcTarget - cOutputString );
+
+ /* If the message is to be logged to a UDP port then it can be sent directly
+ because it only uses FreeRTOS function (not Win32 functions). */
+ if( xUDPLoggingUsed != pdFALSE )
+ {
+ if( ( xPrintSocket == FREERTOS_INVALID_SOCKET ) && ( FreeRTOS_IsNetworkUp() != pdFALSE ) )
+ {
+ /* Create and bind the socket to which print messages are sent. The
+ xTimerPendFunctionCall() function is used even though this is
+ not an interrupt because this function is called from the IP task
+ and the IP task cannot itself wait for a socket to bind. The
+ parameters to prvCreatePrintSocket() are not required so set to
+ NULL or 0. */
+ xTimerPendFunctionCall( prvCreatePrintSocket, NULL, 0, dlDONT_BLOCK );
+ }
+
+ if( xPrintSocket != FREERTOS_INVALID_SOCKET )
+ {
+ FreeRTOS_sendto( xPrintSocket, cOutputString, xLength, 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) );
+
+ /* Just because the UDP data logger I'm using is dumb. */
+ FreeRTOS_sendto( xPrintSocket, "\r", sizeof( char ), 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) );
+ }
+ }
+
+ /* If logging is also to go to either stdout or a disk file then it cannot
+ be output here - so instead write the message to the stream buffer and wake
+ the Win32 thread which will read it from the stream buffer and perform the
+ actual output. */
+ if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) )
+ {
+ configASSERT( xLogStreamBuffer );
+
+ /* How much space is in the buffer? */
+ xLength2 = uxStreamBufferGetSpace( xLogStreamBuffer );
+
+ /* There must be enough space to write both the string and the length of
+ the string. */
+ if( xLength2 >= ( xLength + sizeof( xLength ) ) )
+ {
+ /* First write in the length of the data, then write in the data
+ itself. Raising the thread priority is used as a critical section
+ as there are potentially multiple writers. The stream buffer is
+ only thread safe when there is a single writer (likewise for
+ reading from the buffer). */
+ xCurrentTask = GetCurrentThread();
+ iOriginalPriority = GetThreadPriority( xCurrentTask );
+ SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
+ uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) &( xLength ), sizeof( xLength ) );
+ uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) cOutputString, xLength );
+ SetThreadPriority( GetCurrentThread(), iOriginalPriority );
+ }
+
+ /* xDirectPrint is initialised to pdTRUE, and while it remains true the
+ logging output function is called directly. When the system is running
+ the output function cannot be called directly because it would get
+ called from both FreeRTOS tasks and Win32 threads - so instead wake the
+ Win32 thread responsible for the actual output. */
+ if( xDirectPrint != pdFALSE )
+ {
+ /* While starting up, the thread which calls prvWin32LoggingThread()
+ is not running yet and xDirectPrint will be pdTRUE. */
+ prvLoggingFlushBuffer();
+ }
+ else if( pvLoggingThreadEvent != NULL )
+ {
+ /* While running, wake up prvWin32LoggingThread() to send the
+ logging data. */
+ SetEvent( pvLoggingThreadEvent );
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvLoggingFlushBuffer( void )
+{
+size_t xLength;
+char cPrintString[ dlMAX_PRINT_STRING_LENGTH ];
+
+ /* Is there more than the length value stored in the circular buffer
+ used to pass data from the FreeRTOS simulator into this Win32 thread? */
+ while( uxStreamBufferGetSize( xLogStreamBuffer ) > sizeof( xLength ) )
+ {
+ memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH );
+ uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE );
+ uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) cPrintString, xLength, pdFALSE );
+
+ /* Write the message to standard out if requested to do so when
+ vLoggingInit() was called, or if the network is not yet up. */
+ if( ( xStdoutLoggingUsed != pdFALSE ) || ( FreeRTOS_IsNetworkUp() == pdFALSE ) )
+ {
+ /* Write the message to stdout. */
+ printf( "%s", cPrintString ); /*_RB_ Replace with _write(). */
+ }
+
+ /* Write the message to a file if requested to do so when
+ vLoggingInit() was called. */
+ if( xDiskFileLoggingUsed != pdFALSE )
+ {
+ prvLogToFile( cPrintString, xLength );
+ }
+ }
+
+ prvFileClose();
+}
+/*-----------------------------------------------------------*/
+
+static DWORD WINAPI prvWin32LoggingThread( void *pvParameter )
+{
+const DWORD xMaxWait = 1000;
+
+ ( void ) pvParameter;
+
+ /* From now on, prvLoggingFlushBuffer() will only be called from this
+ Windows thread */
+ xDirectPrint = pdFALSE;
+
+ for( ;; )
+ {
+ /* Wait to be told there are message waiting to be logged. */
+ WaitForSingleObject( pvLoggingThreadEvent, xMaxWait );
+
+ /* Write out all waiting messages. */
+ prvLoggingFlushBuffer();
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvFileLoggingInit( void )
+{
+FILE *pxHandle = fopen( pcLogFileName, "a" );
+
+ if( pxHandle != NULL )
+ {
+ fseek( pxHandle, SEEK_END, 0ul );
+ ulSizeOfLoggingFile = ftell( pxHandle );
+ fclose( pxHandle );
+ }
+ else
+ {
+ ulSizeOfLoggingFile = 0ul;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvFileClose( void )
+{
+ if( pxLoggingFileHandle != NULL )
+ {
+ fclose( pxLoggingFileHandle );
+ pxLoggingFileHandle = NULL;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvLogToFile( const char *pcMessage, size_t xLength )
+{
+ if( pxLoggingFileHandle == NULL )
+ {
+ pxLoggingFileHandle = fopen( pcLogFileName, "a" );
+ }
+
+ if( pxLoggingFileHandle != NULL )
+ {
+ fwrite( pcMessage, 1, xLength, pxLoggingFileHandle );
+ ulSizeOfLoggingFile += xLength;
+
+ /* If the file has grown to its maximum permissible size then close and
+ rename it - then start with a new file. */
+ if( ulSizeOfLoggingFile > ( size_t ) dlLOGGING_FILE_SIZE )
+ {
+ prvFileClose();
+ if( _access( pcFullLogFileName, 00 ) == 0 )
+ {
+ remove( pcFullLogFileName );
+ }
+ rename( pcLogFileName, pcFullLogFileName );
+ ulSizeOfLoggingFile = 0;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/demo_logging.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/demo_logging.h
new file mode 100644
index 000000000..e64ab70e8
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/demo_logging.h
@@ -0,0 +1,89 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+#ifndef DEMO_LOGGING_H
+#define DEMO_LOGGING_H
+
+/*
+ * Initialise a logging system that can be used from FreeRTOS tasks and Win32
+ * threads. Do not call printf() directly while the scheduler is running.
+ *
+ * Set xLogToStdout, xLogToFile and xLogToUDP to either pdTRUE or pdFALSE to
+ * lot to stdout, a disk file and a UDP port respectively.
+ *
+ * If xLogToUDP is pdTRUE then ulRemoteIPAddress and usRemotePort must be set
+ * to the IP address and port number to which UDP log messages will be sent.
+ */
+void vLoggingInit( BaseType_t xLogToStdout,
+ BaseType_t xLogToFile,
+ BaseType_t xLogToUDP,
+ uint32_t ulRemoteIPAddress,
+ uint16_t usRemotePort );
+
+#endif /* DEMO_LOGGING_H */
+
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/main.c b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/main.c
new file mode 100644
index 000000000..c008f3749
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/main.c
@@ -0,0 +1,380 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * This project is a cut down version of the project described on the following
+ * link. Only the simple UDP client and server and the TCP echo clients are
+ * included in the build:
+ * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html
+ */
+
+/* Standard includes. */
+#include <stdio.h>
+#include <time.h>
+
+/* FreeRTOS includes. */
+#include <FreeRTOS.h>
+#include "task.h"
+
+/* Demo application includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "SimpleUDPClientAndServer.h"
+#include "TCPEchoClient_SingleTasks.h"
+#include "demo_logging.h"
+
+/* Simple UDP client and server task parameters. */
+#define mainSIMPLE_UDP_CLIENT_SERVER_TASK_PRIORITY ( tskIDLE_PRIORITY )
+#define mainSIMPLE_UDP_CLIENT_SERVER_PORT ( 5005UL )
+
+/* Echo client task parameters - used for both TCP and UDP echo clients. */
+#define mainECHO_CLIENT_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 ) /* Not used in the Windows port. */
+#define mainECHO_CLIENT_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
+
+/* Define a name that will be used for LLMNR and NBNS searches. */
+#define mainHOST_NAME "RTOSDemo"
+#define mainDEVICE_NICK_NAME "windows_demo"
+
+/* Set the following constants to 1 or 0 to define which tasks to include and
+exclude:
+
+mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS: When set to 1 two UDP client tasks
+and two UDP server tasks are created. The clients talk to the servers. One set
+of tasks use the standard sockets interface, and the other the zero copy sockets
+interface. These tasks are self checking and will trigger a configASSERT() if
+they detect a difference in the data that is received from that which was sent.
+As these tasks use UDP, and can therefore loose packets, they will cause
+configASSERT() to be called when they are run in a less than perfect networking
+environment.
+
+mainCREATE_TCP_ECHO_TASKS_SINGLE: When set to 1 a set of tasks are created that
+send TCP echo requests to the standard echo port (port 7), then wait for and
+verify the echo reply, from within the same task (Tx and Rx are performed in the
+same RTOS task). The IP address of the echo server must be configured using the
+configECHO_SERVER_ADDR0 to configECHO_SERVER_ADDR3 constants in
+FreeRTOSConfig.h.
+*/
+#define mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS 1
+#define mainCREATE_TCP_ECHO_TASKS_SINGLE 1
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Just seeds the simple pseudo random number generator.
+ */
+static void prvSRand( UBaseType_t ulSeed );
+
+/*
+ * Miscellaneous initialisation including preparing the logging and seeding the
+ * random number generator.
+ */
+static void prvMiscInitialisation( void );
+
+/* The default IP and MAC address used by the demo. The address configuration
+defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is
+1 but a DHCP server could not be contacted. See the online documentation for
+more information. */
+static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 };
+static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 };
+static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 };
+static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 };
+
+/* Set the following constant to pdTRUE to log using the method indicated by the
+name of the constant, or pdFALSE to not log using the method indicated by the
+name of the constant. Options include to standard out (xLogToStdout), to a disk
+file (xLogToFile), and to a UDP port (xLogToUDP). If xLogToUDP is set to pdTRUE
+then UDP messages are sent to the IP address configured as the echo server
+address (see the configECHO_SERVER_ADDR0 definitions in FreeRTOSConfig.h) and
+the port number set by configPRINT_PORT in FreeRTOSConfig.h. */
+const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE;
+
+/* Default MAC address configuration. The demo creates a virtual network
+connection that uses this MAC address by accessing the raw Ethernet data
+to and from a real network connection on the host PC. See the
+configNETWORK_INTERFACE_TO_USE definition for information on how to configure
+the real network connection to use. */
+const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 };
+
+/* Use by the pseudo random number generator. */
+static UBaseType_t ulNextRand;
+
+/*-----------------------------------------------------------*/
+
+int main( void )
+{
+const uint32_t ulLongTime_ms = pdMS_TO_TICKS( 1000UL );
+
+ /*
+ * Instructions for using this project are provided on:
+ * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html
+ */
+
+ /* Miscellaneous initialisation including preparing the logging and seeding
+ the random number generator. */
+ prvMiscInitialisation();
+
+ /* Initialise the network interface.
+
+ ***NOTE*** Tasks that use the network are created in the network event hook
+ when the network is connected and ready for use (see the definition of
+ vApplicationIPNetworkEventHook() below). The address values passed in here
+ are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1
+ but a DHCP server cannot be contacted. */
+ FreeRTOS_debug_printf( ( "FreeRTOS_IPInit\n" ) );
+ FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );
+
+ /* Start the RTOS scheduler. */
+ FreeRTOS_debug_printf( ("vTaskStartScheduler\n") );
+ vTaskStartScheduler();
+
+ /* If all is well, the scheduler will now be running, and the following
+ line will never be reached. If the following line does execute, then
+ there was insufficient FreeRTOS heap memory available for the idle and/or
+ timer tasks to be created. See the memory management section on the
+ FreeRTOS web site for more details (this is standard text that is not not
+ really applicable to the Win32 simulator port). */
+ for( ;; )
+ {
+ Sleep( ulLongTime_ms );
+ }
+}
+/*-----------------------------------------------------------*/
+
+void vApplicationIdleHook( void )
+{
+const uint32_t ulMSToSleep = 1;
+
+ /* This is just a trivial example of an idle hook. It is called on each
+ cycle of the idle task if configUSE_IDLE_HOOK is set to 1 in
+ FreeRTOSConfig.h. It must *NOT* attempt to block. In this case the
+ idle task just sleeps to lower the CPU usage. */
+ Sleep( ulMSToSleep );
+}
+/*-----------------------------------------------------------*/
+
+void vAssertCalled( const char *pcFile, uint32_t ulLine )
+{
+const uint32_t ulLongSleep = 1000UL;
+volatile uint32_t ulBlockVariable = 0UL;
+volatile char *pcFileName = ( volatile char * ) pcFile;
+volatile uint32_t ulLineNumber = ulLine;
+
+ ( void ) pcFileName;
+ ( void ) ulLineNumber;
+
+ FreeRTOS_debug_printf( ( "vAssertCalled( %s, %ld\n", pcFile, ulLine ) );
+
+ /* Setting ulBlockVariable to a non-zero value in the debugger will allow
+ this function to be exited. */
+ taskDISABLE_INTERRUPTS();
+ {
+ while( ulBlockVariable == 0UL )
+ {
+ Sleep( ulLongSleep );
+ }
+ }
+ taskENABLE_INTERRUPTS();
+}
+/*-----------------------------------------------------------*/
+
+/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect
+events are only received if implemented in the MAC driver. */
+void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
+{
+uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress;
+char cBuffer[ 16 ];
+static BaseType_t xTasksAlreadyCreated = pdFALSE;
+
+ /* If the network has just come up...*/
+ if( eNetworkEvent == eNetworkUp )
+ {
+ /* Create the tasks that use the IP stack if they have not already been
+ created. */
+ if( xTasksAlreadyCreated == pdFALSE )
+ {
+ /* See the comments above the definitions of these pre-processor
+ macros at the top of this file for a description of the individual
+ demo tasks. */
+ #if( mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS == 1 )
+ {
+ vStartSimpleUDPClientServerTasks( configMINIMAL_STACK_SIZE, mainSIMPLE_UDP_CLIENT_SERVER_PORT, mainSIMPLE_UDP_CLIENT_SERVER_TASK_PRIORITY );
+ }
+ #endif /* mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS */
+
+ #if( mainCREATE_TCP_ECHO_TASKS_SINGLE == 1 )
+ {
+ vStartTCPEchoClientTasks_SingleTasks( mainECHO_CLIENT_TASK_STACK_SIZE, mainECHO_CLIENT_TASK_PRIORITY );
+ }
+ #endif /* mainCREATE_TCP_ECHO_TASKS_SINGLE */
+
+ xTasksAlreadyCreated = pdTRUE;
+ }
+
+ /* Print out the network configuration, which may have come from a DHCP
+ server. */
+ FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress );
+ FreeRTOS_inet_ntoa( ulIPAddress, cBuffer );
+ FreeRTOS_printf( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) );
+
+ FreeRTOS_inet_ntoa( ulNetMask, cBuffer );
+ FreeRTOS_printf( ( "Subnet Mask: %s\r\n", cBuffer ) );
+
+ FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer );
+ FreeRTOS_printf( ( "Gateway Address: %s\r\n", cBuffer ) );
+
+ FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer );
+ FreeRTOS_printf( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) );
+ }
+}
+/*-----------------------------------------------------------*/
+
+void vApplicationMallocFailedHook( void )
+{
+ /* Called if a call to pvPortMalloc() fails because there is insufficient
+ free memory available in the FreeRTOS heap. pvPortMalloc() is called
+ internally by FreeRTOS API functions that create tasks, queues, software
+ timers, and semaphores. The size of the FreeRTOS heap is set by the
+ configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */
+ vAssertCalled( __FILE__, __LINE__ );
+}
+/*-----------------------------------------------------------*/
+
+UBaseType_t uxRand( void )
+{
+const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;
+
+ /* Utility function to generate a pseudo random number. */
+
+ ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;
+ return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL );
+}
+/*-----------------------------------------------------------*/
+
+static void prvSRand( UBaseType_t ulSeed )
+{
+ /* Utility function to seed the pseudo random number generator. */
+ ulNextRand = ulSeed;
+}
+/*-----------------------------------------------------------*/
+
+static void prvMiscInitialisation( void )
+{
+time_t xTimeNow;
+uint32_t ulLoggingIPAddress;
+
+ ulLoggingIPAddress = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, configECHO_SERVER_ADDR1, configECHO_SERVER_ADDR2, configECHO_SERVER_ADDR3 );
+ vLoggingInit( xLogToStdout, xLogToFile, xLogToUDP, ulLoggingIPAddress, configPRINT_PORT );
+
+ /* Seed the random number generator. */
+ time( &xTimeNow );
+ FreeRTOS_debug_printf( ( "Seed for randomiser: %lu\n", xTimeNow ) );
+ prvSRand( ( uint32_t ) xTimeNow );
+ FreeRTOS_debug_printf( ( "Random numbers: %08X %08X %08X %08X\n", ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32() ) );
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
+
+ const char *pcApplicationHostnameHook( void )
+ {
+ /* Assign the name "FreeRTOS" to this network node. This function will
+ be called during the DHCP: the machine will be registered with an IP
+ address plus this name. */
+ return mainHOST_NAME;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 )
+
+ BaseType_t xApplicationDNSQueryHook( const char *pcName )
+ {
+ BaseType_t xReturn;
+
+ /* Determine if a name lookup is for this node. Two names are given
+ to this node: that returned by pcApplicationHostnameHook() and that set
+ by mainDEVICE_NICK_NAME. */
+ if( _stricmp( pcName, pcApplicationHostnameHook() ) == 0 )
+ {
+ xReturn = pdPASS;
+ }
+ else if( _stricmp( pcName, mainDEVICE_NICK_NAME ) == 0 )
+ {
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+
+ return xReturn;
+ }
+
+#endif
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/printf-stdarg.c b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/printf-stdarg.c
new file mode 100644
index 000000000..5505535c1
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Minimal_Windows_Simulator/printf-stdarg.c
@@ -0,0 +1,667 @@
+/*
+ Copyright 2001, 2002 Georges Menie (www.menie.org)
+ stdarg version contributed by Christian Ettinger
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ Changes for the FreeRTOS ports:
+
+ - The dot in "%-8.8s"
+ - The specifiers 'l' (long) and 'L' (long long)
+ - The specifier 'u' for unsigned
+ - Dot notation for IP addresses:
+ sprintf("IP = %xip\n", 0xC0A80164);
+ will produce "IP = 192.168.1.100\n"
+*/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "FreeRTOS.h"
+
+#define PAD_RIGHT 1
+#define PAD_ZERO 2
+
+/*
+ * Return 1 for readable, 2 for writeable, 3 for both.
+ * Function must be provided by the application.
+ */
+extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress );
+
+extern void vOutputChar( const char cChar, const TickType_t xTicksToWait );
+static const TickType_t xTicksToWait = pdMS_TO_TICKS( 20 );
+
+struct xPrintFlags
+{
+ int base;
+ int width;
+ int printLimit;
+ unsigned
+ pad : 8,
+ letBase : 8,
+ isSigned : 1,
+ isNumber : 1,
+ long32 : 1,
+ long64 : 1;
+};
+
+struct SStringBuf
+{
+ char *str;
+ const char *orgStr;
+ const char *nulPos;
+ int curLen;
+ struct xPrintFlags flags;
+};
+
+static void strbuf_init( struct SStringBuf *apStr, char *apBuf, const char *apMaxStr )
+{
+ apStr->str = apBuf;
+ apStr->orgStr = apBuf;
+ apStr->nulPos = apMaxStr-1;
+ apStr->curLen = 0;
+
+ memset( &apStr->flags, '\0', sizeof( apStr->flags ) );
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t strbuf_printchar( struct SStringBuf *apStr, int c )
+{
+ if( apStr->str == NULL )
+ {
+ vOutputChar( ( char ) c, xTicksToWait );
+ apStr->curLen++;
+ return pdTRUE;
+ }
+ if( apStr->str < apStr->nulPos )
+ {
+ *( apStr->str++ ) = c;
+ apStr->curLen++;
+ return pdTRUE;
+ }
+ if( apStr->str == apStr->nulPos )
+ {
+ *( apStr->str++ ) = '\0';
+ }
+ return pdFALSE;
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE BaseType_t strbuf_printchar_inline( struct SStringBuf *apStr, int c )
+{
+ if( apStr->str == NULL )
+ {
+ vOutputChar( ( char ) c, xTicksToWait );
+ if( c == 0 )
+ {
+ return pdFALSE;
+ }
+ apStr->curLen++;
+ return pdTRUE;
+ }
+ if( apStr->str < apStr->nulPos )
+ {
+ *(apStr->str++) = c;
+ if( c == 0 )
+ {
+ return pdFALSE;
+ }
+ apStr->curLen++;
+ return pdTRUE;
+ }
+ if( apStr->str == apStr->nulPos )
+ {
+ *( apStr->str++ ) = '\0';
+ }
+ return pdFALSE;
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE int i2hex( int aCh )
+{
+int iResult;
+
+ if( aCh < 10 )
+ {
+ iResult = '0' + aCh;
+ }
+ else
+ {
+ iResult = 'A' + aCh - 10;
+ }
+
+ return iResult;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prints(struct SStringBuf *apBuf, const char *apString )
+{
+ register int padchar = ' ';
+ int i,len;
+
+ if( xApplicationMemoryPermissions( ( uint32_t )apString ) == 0 )
+ {
+ /* The user has probably made a mistake with the parameter
+ for '%s', the memory is not readbale. */
+ apString = "INV_MEM";
+ }
+
+ if( apBuf->flags.width > 0 )
+ {
+ register int len = 0;
+ register const char *ptr;
+ for( ptr = apString; *ptr; ++ptr )
+ {
+ ++len;
+ }
+
+ if( len >= apBuf->flags.width )
+ {
+ apBuf->flags.width = 0;
+ }
+ else
+ {
+ apBuf->flags.width -= len;
+ }
+
+ if( apBuf->flags.pad & PAD_ZERO )
+ {
+ padchar = '0';
+ }
+ }
+ if( ( apBuf->flags.pad & PAD_RIGHT ) == 0 )
+ {
+ for( ; apBuf->flags.width > 0; --apBuf->flags.width )
+ {
+ if( strbuf_printchar( apBuf, padchar ) == 0 )
+ {
+ return pdFALSE;
+ }
+ }
+ }
+ if( ( apBuf->flags.isNumber == pdTRUE ) && ( apBuf->flags.pad == pdTRUE ) )
+ {
+ /* The string to print represents an integer number.
+ * In this case, printLimit is the min number of digits to print
+ * If the length of the number to print is less than the min nb of i
+ * digits to display, we add 0 before printing the number
+ */
+ len = strlen( apString );
+
+ if( len < apBuf->flags.printLimit )
+ {
+ i = apBuf->flags.printLimit - len;
+ for( ; i; i-- )
+ {
+ if( strbuf_printchar( apBuf, '0' ) == 0 )
+ {
+ return pdFALSE;
+ }
+ }
+ }
+ }
+ /* The string to print is not the result of a number conversion to ascii.
+ * For a string, printLimit is the max number of characters to display
+ */
+ for( ; apBuf->flags.printLimit && *apString ; ++apString, --apBuf->flags.printLimit )
+ {
+ if( !strbuf_printchar( apBuf, *apString ) )
+ {
+ return pdFALSE;
+ }
+ }
+
+ for( ; apBuf->flags.width > 0; --apBuf->flags.width )
+ {
+ if( !strbuf_printchar( apBuf, padchar ) )
+ {
+ return pdFALSE;
+ }
+ }
+
+ return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+/* the following should be enough for 32 bit int */
+#define PRINT_BUF_LEN 12 /* to print 4294967296 */
+
+#if SPRINTF_LONG_LONG
+#warning 64-bit libraries will be included as well
+static BaseType_t printll( struct SStringBuf *apBuf, long long i )
+{
+ char print_buf[ 2 * PRINT_BUF_LEN ];
+ register char *s;
+ register int t, neg = 0;
+ register unsigned long long u = i;
+ lldiv_t lldiv_result;
+
+/* typedef struct
+ * {
+ * long long int quot; // quotient
+ * long long int rem; // remainder
+ * } lldiv_t;
+ */
+
+ apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */
+ if( i == 0LL )
+ {
+ print_buf[ 0 ] = '0';
+ print_buf[ 1 ] = '\0';
+ return prints( apBuf, print_buf );
+ }
+
+ if( ( apBuf->flags.isSigned == pdTRUE ) && ( apBuf->flags.base == 10 ) && ( i < 0LL ) )
+ {
+ neg = 1;
+ u = -i;
+ }
+
+ s = print_buf + sizeof( print_buf ) - 1;
+
+ *s = '\0';
+ /* 18446744073709551616 */
+ while( u != 0 )
+ {
+ lldiv_result = lldiv( u, ( unsigned long long ) apBuf->flags.base );
+ t = lldiv_result.rem;
+ if( t >= 10 )
+ {
+ t += apBuf->flags.letBase - '0' - 10;
+ }
+ *( --s ) = t + '0';
+ u = lldiv_result.quot;
+ }
+
+ if( neg != 0 )
+ {
+ if( ( apBuf->flags.width != 0 ) && ( apBuf->flags.pad & PAD_ZERO ) )
+ {
+ if( !strbuf_printchar( apBuf, '-' ) )
+ {
+ return pdFALSE;
+ }
+ --apBuf->flags.width;
+ }
+ else
+ {
+ *( --s ) = '-';
+ }
+ }
+
+ return prints( apBuf, s );
+}
+#endif /* SPRINTF_LONG_LONG */
+/*-----------------------------------------------------------*/
+
+static BaseType_t printi( struct SStringBuf *apBuf, int i )
+{
+ char print_buf[ PRINT_BUF_LEN ];
+ register char *s;
+ register int t, neg = 0;
+ register unsigned int u = i;
+ register unsigned base = apBuf->flags.base;
+
+ apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */
+
+ if( i == 0 )
+ {
+ print_buf[ 0 ] = '0';
+ print_buf[ 1 ] = '\0';
+ return prints( apBuf, print_buf );
+ }
+
+ if( ( apBuf->flags.isSigned == pdTRUE ) && ( base == 10 ) && ( i < 0 ) )
+ {
+ neg = 1;
+ u = -i;
+ }
+
+ s = print_buf + sizeof( print_buf ) - 1;
+
+ *s = '\0';
+ switch( base )
+ {
+ case 16:
+ while( u != 0 )
+ {
+ t = u & 0xF;
+ if( t >= 10 )
+ {
+ t += apBuf->flags.letBase - '0' - 10;
+ }
+ *( --s ) = t + '0';
+ u >>= 4;
+ }
+ break;
+
+ case 8:
+ case 10:
+ /* GCC compiles very efficient */
+ while( u )
+ {
+ t = u % base;
+ *( --s ) = t + '0';
+ u /= base;
+ }
+ break;
+/*
+ // The generic case, not yet in use
+ default:
+ while( u )
+ {
+ t = u % base;
+ if( t >= 10)
+ {
+ t += apBuf->flags.letBase - '0' - 10;
+ }
+ *( --s ) = t + '0';
+ u /= base;
+ }
+ break;
+*/
+ }
+
+ if( neg != 0 )
+ {
+ if( apBuf->flags.width && (apBuf->flags.pad & PAD_ZERO ) )
+ {
+ if( strbuf_printchar( apBuf, '-' ) == 0 )
+ {
+ return pdFALSE;
+ }
+ --apBuf->flags.width;
+ }
+ else
+ {
+ *( --s ) = '-';
+ }
+ }
+
+ return prints( apBuf, s );
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t printIp(struct SStringBuf *apBuf, unsigned i )
+{
+ char print_buf[16];
+
+ sprintf( print_buf, "%u.%u.%u.%u",
+ i >> 24,
+ ( i >> 16 ) & 0xff,
+ ( i >> 8 ) & 0xff,
+ i & 0xff );
+ apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */
+ prints( apBuf, print_buf );
+
+ return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+static void tiny_print( struct SStringBuf *apBuf, const char *format, va_list args )
+{
+ char scr[2];
+
+ for( ; ; )
+ {
+ int ch = *( format++ );
+
+ if( ch != '%' )
+ {
+ do
+ {
+ /* Put the most like flow in a small loop */
+ if( strbuf_printchar_inline( apBuf, ch ) == 0 )
+ {
+ return;
+ }
+ ch = *( format++ );
+ } while( ch != '%' );
+ }
+ ch = *( format++ );
+ /* Now ch has character after '%', format pointing to next */
+
+ if( ch == '\0' )
+ {
+ break;
+ }
+ if( ch == '%' )
+ {
+ if( strbuf_printchar( apBuf, ch ) == 0 )
+ {
+ return;
+ }
+ continue;
+ }
+ memset( &apBuf->flags, '\0', sizeof( apBuf->flags ) );
+
+ if( ch == '-' )
+ {
+ ch = *( format++ );
+ apBuf->flags.pad = PAD_RIGHT;
+ }
+ while( ch == '0' )
+ {
+ ch = *( format++ );
+ apBuf->flags.pad |= PAD_ZERO;
+ }
+ if( ch == '*' )
+ {
+ ch = *( format++ );
+ apBuf->flags.width = va_arg( args, int );
+ }
+ else
+ {
+ while( ch >= '0' && ch <= '9' )
+ {
+ apBuf->flags.width *= 10;
+ apBuf->flags.width += ch - '0';
+ ch = *( format++ );
+ }
+ }
+ if( ch == '.' )
+ {
+ ch = *( format++ );
+ if( ch == '*' )
+ {
+ apBuf->flags.printLimit = va_arg( args, int );
+ ch = *( format++ );
+ }
+ else
+ {
+ while( ch >= '0' && ch <= '9' )
+ {
+ apBuf->flags.printLimit *= 10;
+ apBuf->flags.printLimit += ch - '0';
+ ch = *( format++ );
+ }
+ }
+ }
+ if( apBuf->flags.printLimit == 0 )
+ {
+ apBuf->flags.printLimit--; /* -1: make it unlimited */
+ }
+ if( ch == 's' )
+ {
+ register char *s = ( char * )va_arg( args, int );
+ if( prints( apBuf, s ? s : "(null)" ) == 0 )
+ {
+ break;
+ }
+ continue;
+ }
+ if( ch == 'c' )
+ {
+ /* char are converted to int then pushed on the stack */
+ scr[0] = ( char ) va_arg( args, int );
+
+ if( strbuf_printchar( apBuf, scr[0] ) == 0 )
+ {
+ return;
+ }
+
+ continue;
+ }
+ if( ch == 'l' )
+ {
+ ch = *( format++ );
+ apBuf->flags.long32 = 1;
+ /* Makes not difference as u32 == long */
+ }
+ if( ch == 'L' )
+ {
+ ch = *( format++ );
+ apBuf->flags.long64 = 1;
+ /* Does make a difference */
+ }
+ apBuf->flags.base = 10;
+ apBuf->flags.letBase = 'a';
+
+ if( ch == 'd' || ch == 'u' )
+ {
+ apBuf->flags.isSigned = ( ch == 'd' );
+#if SPRINTF_LONG_LONG
+ if( apBuf->flags.long64 != pdFALSE )
+ {
+ if( printll( apBuf, va_arg( args, long long ) ) == 0 )
+ {
+ break;
+ }
+ } else
+#endif /* SPRINTF_LONG_LONG */
+ if( printi( apBuf, va_arg( args, int ) ) == 0 )
+ {
+ break;
+ }
+ continue;
+ }
+
+ apBuf->flags.base = 16; /* From here all hexadecimal */
+
+ if( ch == 'x' && format[0] == 'i' && format[1] == 'p' )
+ {
+ format += 2; /* eat the "xi" of "xip" */
+ /* Will use base 10 again */
+ if( printIp( apBuf, va_arg( args, int ) ) == 0 )
+ {
+ break;
+ }
+ continue;
+ }
+ if( ch == 'x' || ch == 'X' || ch == 'p' || ch == 'o' )
+ {
+ if( ch == 'X' )
+ {
+ apBuf->flags.letBase = 'A';
+ }
+ else if( ch == 'o' )
+ {
+ apBuf->flags.base = 8;
+ }
+#if SPRINTF_LONG_LONG
+ if( apBuf->flags.long64 != pdFALSE )
+ {
+ if( printll( apBuf, va_arg( args, long long ) ) == 0 )
+ {
+ break;
+ }
+ } else
+#endif /* SPRINTF_LONG_LONG */
+ if( printi( apBuf, va_arg( args, int ) ) == 0 )
+ {
+ break;
+ }
+ continue;
+ }
+ }
+ strbuf_printchar( apBuf, '\0' );
+}
+/*-----------------------------------------------------------*/
+
+int vsnprintf( char *apBuf, size_t aMaxLen, const char *apFmt, va_list args )
+{
+ struct SStringBuf strBuf;
+ strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen );
+ tiny_print( &strBuf, apFmt, args );
+
+ return strBuf.curLen;
+}
+/*-----------------------------------------------------------*/
+
+int snprintf( char *apBuf, size_t aMaxLen, const char *apFmt, ... )
+{
+ va_list args;
+
+ va_start( args, apFmt );
+ struct SStringBuf strBuf;
+ strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen );
+ tiny_print( &strBuf, apFmt, args );
+ va_end( args );
+
+ return strBuf.curLen;
+}
+/*-----------------------------------------------------------*/
+
+int sprintf( char *apBuf, const char *apFmt, ... )
+{
+ va_list args;
+
+ va_start( args, apFmt );
+ struct SStringBuf strBuf;
+ strbuf_init( &strBuf, apBuf, ( const char * )apBuf + 1024 );
+ tiny_print( &strBuf, apFmt, args );
+ va_end( args );
+
+ return strBuf.curLen;
+}
+/*-----------------------------------------------------------*/
+
+int vsprintf( char *apBuf, const char *apFmt, va_list args )
+{
+ struct SStringBuf strBuf;
+ strbuf_init( &strBuf, apBuf, ( const char* ) apBuf + 1024 );
+ tiny_print( &strBuf, apFmt, args );
+
+ return strBuf.curLen;
+}
+/*-----------------------------------------------------------*/
+
+const char *mkSize (unsigned long long aSize, char *apBuf, int aLen)
+{
+static char retString[33];
+size_t gb, mb, kb, sb;
+
+ if (apBuf == NULL) {
+ apBuf = retString;
+ aLen = sizeof( retString );
+ }
+ gb = aSize / (1024*1024*1024);
+ aSize -= gb * (1024*1024*1024);
+ mb = aSize / (1024*1024);
+ aSize -= mb * (1024*1024);
+ kb = aSize / (1024);
+ aSize -= kb * (1024);
+ sb = aSize;
+ if( gb )
+ {
+ snprintf (apBuf, aLen, "%u.%02u GB", ( unsigned ) gb, ( unsigned ) ( ( 100 * mb ) / 1024ul ) );
+ }
+ else if( mb )
+ {
+ snprintf (apBuf, aLen, "%u.%02u MB", ( unsigned ) mb, ( unsigned ) ( ( 100 * kb) / 1024ul ) );
+ }
+ else if( kb != 0ul )
+ {
+ snprintf (apBuf, aLen, "%u.%02u KB", ( unsigned ) kb, ( unsigned ) ( ( 100 * sb) / 1024ul ) );
+ }
+ else
+ {
+ snprintf (apBuf, aLen, "%u bytes", ( unsigned ) sb);
+ }
+ return apBuf;
+}
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/.cproject b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/.cproject
index ed0774e30..b97ce71fc 100644
--- a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/.cproject
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/.cproject
@@ -5,14 +5,14 @@
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.crt.advproject.config.exe.debug.56486929" moduleId="org.eclipse.cdt.core.settings" name="Debug">
<externalSettings/>
<extensions>
+ <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+ <extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
- <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
- <extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@@ -79,6 +79,7 @@
<option id="gnu.c.link.option.nodeflibs.2072403274" name="Do not use default libraries (-nodefaultlibs)" superClass="gnu.c.link.option.nodeflibs" value="false" valueType="boolean"/>
<option id="com.crt.advproject.link.gcc.multicore.slave.1911982348" name="Multicore slave" superClass="com.crt.advproject.link.gcc.multicore.slave"/>
<option id="com.crt.advproject.link.gcc.multicore.master.userobjs.502901386" superClass="com.crt.advproject.link.gcc.multicore.master.userobjs" valueType="userObjs"/>
+ <option id="com.crt.advproject.link.memory.heapAndStack.1733504656" superClass="com.crt.advproject.link.memory.heapAndStack" value="&amp;Heap:Default;Post Data;Default&amp;Stack:Default;End;Default" valueType="string"/>
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.1085761099" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
@@ -86,22 +87,7 @@
</tool>
</toolChain>
</folderInfo>
- <folderInfo id="com.crt.advproject.config.exe.debug.56486929.1781697322" name="/" resourcePath="ThirdParty/CMSISv2p10_LPC18xx_DriverLib">
- <toolChain id="com.crt.advproject.toolchain.exe.debug.222538953" name="Code Red MCU Tools" superClass="com.crt.advproject.toolchain.exe.debug" unusedChildren="">
- <targetPlatform binaryParser="org.eclipse.cdt.core.ELF;org.eclipse.cdt.core.GNU_ELF" id="com.crt.advproject.platform.exe.debug" name="ARM-based MCU (Debug)" superClass="com.crt.advproject.platform.exe.debug"/>
- <tool id="com.crt.advproject.cpp.exe.debug.906161578" name="MCU C++ Compiler" superClass="com.crt.advproject.cpp.exe.debug.359174792"/>
- <tool id="com.crt.advproject.gcc.exe.debug.1015468334" name="MCU C Compiler" superClass="com.crt.advproject.gcc.exe.debug.517029683">
- <option id="com.crt.advproject.gcc.exe.debug.option.optimization.level.2021633161" name="Optimization Level" superClass="com.crt.advproject.gcc.exe.debug.option.optimization.level" value="gnu.c.optimization.level.size" valueType="enumerated"/>
- <inputType id="com.crt.advproject.compiler.input.1878730423" superClass="com.crt.advproject.compiler.input"/>
- </tool>
- <tool id="com.crt.advproject.gas.exe.debug.253843695" name="MCU Assembler" superClass="com.crt.advproject.gas.exe.debug.281614531">
- <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1935362347" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
- <inputType id="com.crt.advproject.assembler.input.190369423" name="Additional Assembly Source Files" superClass="com.crt.advproject.assembler.input"/>
- </tool>
- <tool id="com.crt.advproject.link.cpp.exe.debug.1715304950" name="MCU C++ Linker" superClass="com.crt.advproject.link.cpp.exe.debug.1490011469"/>
- <tool id="com.crt.advproject.link.exe.debug.536813209" name="MCU Linker" superClass="com.crt.advproject.link.exe.debug.1212311005"/>
- </toolChain>
- </folderInfo>
+ <fileInfo id="com.crt.advproject.config.exe.debug.56486929.src/cr_startup_lpc18xx.cpp" name="cr_startup_lpc18xx.cpp" rcbsApplicability="disable" resourcePath="src/cr_startup_lpc18xx.cpp" toolsToInvoke=""/>
<folderInfo id="com.crt.advproject.config.exe.debug.56486929.2106668528" name="/" resourcePath="ThirdParty/USB_CDC">
<toolChain id="com.crt.advproject.toolchain.exe.debug.1865989435" name="Code Red MCU Tools" superClass="com.crt.advproject.toolchain.exe.debug" unusedChildren="">
<targetPlatform binaryParser="org.eclipse.cdt.core.ELF;org.eclipse.cdt.core.GNU_ELF" id="com.crt.advproject.platform.exe.debug" name="ARM-based MCU (Debug)" superClass="com.crt.advproject.platform.exe.debug"/>
@@ -118,7 +104,22 @@
<tool id="com.crt.advproject.link.exe.debug.1734116997" name="MCU Linker" superClass="com.crt.advproject.link.exe.debug.1212311005"/>
</toolChain>
</folderInfo>
- <fileInfo id="com.crt.advproject.config.exe.debug.56486929.src/cr_startup_lpc18xx.cpp" name="cr_startup_lpc18xx.cpp" rcbsApplicability="disable" resourcePath="src/cr_startup_lpc18xx.cpp" toolsToInvoke=""/>
+ <folderInfo id="com.crt.advproject.config.exe.debug.56486929.1781697322" name="/" resourcePath="ThirdParty/CMSISv2p10_LPC18xx_DriverLib">
+ <toolChain id="com.crt.advproject.toolchain.exe.debug.222538953" name="Code Red MCU Tools" superClass="com.crt.advproject.toolchain.exe.debug" unusedChildren="">
+ <targetPlatform binaryParser="org.eclipse.cdt.core.ELF;org.eclipse.cdt.core.GNU_ELF" id="com.crt.advproject.platform.exe.debug" name="ARM-based MCU (Debug)" superClass="com.crt.advproject.platform.exe.debug"/>
+ <tool id="com.crt.advproject.cpp.exe.debug.906161578" name="MCU C++ Compiler" superClass="com.crt.advproject.cpp.exe.debug.359174792"/>
+ <tool id="com.crt.advproject.gcc.exe.debug.1015468334" name="MCU C Compiler" superClass="com.crt.advproject.gcc.exe.debug.517029683">
+ <option id="com.crt.advproject.gcc.exe.debug.option.optimization.level.2021633161" name="Optimization Level" superClass="com.crt.advproject.gcc.exe.debug.option.optimization.level" value="gnu.c.optimization.level.size" valueType="enumerated"/>
+ <inputType id="com.crt.advproject.compiler.input.1878730423" superClass="com.crt.advproject.compiler.input"/>
+ </tool>
+ <tool id="com.crt.advproject.gas.exe.debug.253843695" name="MCU Assembler" superClass="com.crt.advproject.gas.exe.debug.281614531">
+ <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1935362347" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+ <inputType id="com.crt.advproject.assembler.input.190369423" name="Additional Assembly Source Files" superClass="com.crt.advproject.assembler.input"/>
+ </tool>
+ <tool id="com.crt.advproject.link.cpp.exe.debug.1715304950" name="MCU C++ Linker" superClass="com.crt.advproject.link.cpp.exe.debug.1490011469"/>
+ <tool id="com.crt.advproject.link.exe.debug.536813209" name="MCU Linker" superClass="com.crt.advproject.link.exe.debug.1212311005"/>
+ </toolChain>
+ </folderInfo>
<sourceEntries>
<entry excluding="ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_wwdt.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_utils.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_uart.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_timer.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_ssp.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_sct.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_rtc.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_rit.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_qei.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_pwr.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_nvic.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_mcpwm.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_libcfg_default.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_lcd.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_i2s.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_i2c.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_gpdma.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_evrt.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_emc.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_dac.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_can.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_atimer.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/lpc18xx_adc.c|ThirdParty/CMSISv2p10_LPC18xx_DriverLib/src/debug_frmwrk.c" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
@@ -134,7 +135,7 @@
<storageModule moduleId="com.crt.config">
<projectStorage>&lt;?xml version="1.0" encoding="UTF-8"?&gt;&#13;
&lt;TargetConfig&gt;&#13;
-&lt;Properties property_0="" property_2="LPC1850A_4350A_SPIFI.cfx" property_3="NXP" property_4="LPC1830" property_count="5" version="70200"/&gt;&#13;
+&lt;Properties property_2="LPC1850A_4350A_SPIFI.cfx" property_3="NXP" property_4="LPC1830" property_count="5" version="70200"/&gt;&#13;
&lt;infoList vendor="NXP"&gt;&lt;info chip="LPC1830" match_id="0x0" name="LPC1830" resetscript="LPC18LPC43ExternalFLASHBootResetscript.scp" stub="crt_emu_lpc18_43_nxp"&gt;&lt;chip&gt;&lt;name&gt;LPC1830&lt;/name&gt;&#13;
&lt;family&gt;LPC18xx&lt;/family&gt;&#13;
&lt;vendor&gt;NXP (formerly Philips)&lt;/vendor&gt;&#13;
@@ -227,4 +228,6 @@
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.crt.advproject.GCCManagedMakePerProjectProfile"/>
</scannerConfigBuildInfo>
</storageModule>
+ <storageModule moduleId="com.crt.advproject"/>
+ <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
</cproject>
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/CLI-commands.c b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/CLI-commands.c
index 0ff864419..e4f1e6f0f 100644
--- a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/CLI-commands.c
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/CLI-commands.c
@@ -254,7 +254,8 @@ void vRegisterCLICommands( void )
static BaseType_t prvTaskStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
-const char *const pcHeader = "Task State Priority Stack #\r\n************************************************\r\n";
+const char *const pcHeader = " State\tPriority\tStack\t#\r\n************************************************\r\n";
+BaseType_t xSpacePadding;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
@@ -264,6 +265,22 @@ const char *const pcHeader = "Task State Priority Stack #\r\n********
configASSERT( pcWriteBuffer );
/* Generate a table of task stats. */
+ strcpy( pcWriteBuffer, "Task" );
+ pcWriteBuffer += strlen( pcWriteBuffer );
+
+ /* Pad the string "task" with however many bytes necessary to make it the
+ length of a task name. Minus three for the null terminator and half the
+ number of characters in "Task" so the column lines up with the centre of
+ the heading. */
+ for( xSpacePadding = strlen( "Task" ); xSpacePadding < ( configMAX_TASK_NAME_LEN - 3 ); xSpacePadding++ )
+ {
+ /* Add a space to align columns after the task's name. */
+ *pcWriteBuffer = ' ';
+ pcWriteBuffer++;
+
+ /* Ensure always terminated. */
+ *pcWriteBuffer = 0x00;
+ }
strcpy( pcWriteBuffer, pcHeader );
vTaskList( pcWriteBuffer + strlen( pcHeader ) );
@@ -275,7 +292,8 @@ const char *const pcHeader = "Task State Priority Stack #\r\n********
static BaseType_t prvRunTimeStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
-const char * const pcHeader = "Task Abs Time % Time\r\n****************************************\r\n";
+const char * const pcHeader = " Abs Time % Time\r\n****************************************\r\n";
+BaseType_t xSpacePadding;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
@@ -285,6 +303,23 @@ const char * const pcHeader = "Task Abs Time % Time\r\n*********
configASSERT( pcWriteBuffer );
/* Generate a table of task stats. */
+ strcpy( pcWriteBuffer, "Task" );
+ pcWriteBuffer += strlen( pcWriteBuffer );
+
+ /* Pad the string "task" with however many bytes necessary to make it the
+ length of a task name. Minus three for the null terminator and half the
+ number of characters in "Task" so the column lines up with the centre of
+ the heading. */
+ for( xSpacePadding = strlen( "Task" ); xSpacePadding < ( configMAX_TASK_NAME_LEN - 3 ); xSpacePadding++ )
+ {
+ /* Add a space to align columns after the task's name. */
+ *pcWriteBuffer = ' ';
+ pcWriteBuffer++;
+
+ /* Ensure always terminated. */
+ *pcWriteBuffer = 0x00;
+ }
+
strcpy( pcWriteBuffer, pcHeader );
vTaskGetRunTimeStats( pcWriteBuffer + strlen( pcHeader ) );
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/FreeRTOSConfig.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/FreeRTOSConfig.h
index d40c9b269..a805f5e77 100644
--- a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/FreeRTOSConfig.h
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/FreeRTOSConfig.h
@@ -189,7 +189,7 @@ standard names. */
/* Set to 1 to include "trace start" and "trace stop" CLI commands. These
commands start and stop the FreeRTOS+Trace recording. */
-#define configINCLUDE_TRACE_RELATED_CLI_COMMANDS 1
+#define configINCLUDE_TRACE_RELATED_CLI_COMMANDS 0
/* Dimensions a buffer that can be used by the FreeRTOS+CLI command
interpreter. See the FreeRTOS+CLI documentation for more information:
@@ -277,10 +277,8 @@ ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */
#define configNET_MASK2 255
#define configNET_MASK3 0
-#if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1
- /* Only include the trace macro definitions required by FreeRTOS+Trace if
- the trace start and trace stop CLI commands are included. */
- #include "trcKernelPort.h"
-#endif
+/* Only include the trace macro definitions required by FreeRTOS+Trace if
+the trace start and trace stop CLI commands are included. */
+#include "trcRecorder.h"
#endif /* FREERTOS_CONFIG_H */
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/trcConfig.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/trcConfig.h
index 6ff5961a6..f09345f97 100644
--- a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/trcConfig.h
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/trcConfig.h
@@ -1,475 +1,160 @@
-/*******************************************************************************
- * Tracealyzer v2.7.0 Recorder Library
+/*******************************************************************************
+ * Trace Recorder Library for Tracealyzer v3.1.2
* Percepio AB, www.percepio.com
*
* trcConfig.h
*
- * Configuration parameters for the trace recorder library. Before using the
- * trace recorder library, please check that the default settings are
- * appropriate for your system, and if necessary adjust these. Most likely, you
- * will need to adjust the NTask, NISR, NQueue, NMutex and NSemaphore values to
- * reflect the number of such objects in your system. These may be
- * over-approximated, although larger values values implies more RAM usage.
+ * Main configuration parameters for the trace recorder library.
+ * More settings can be found in trcStreamingConfig.h and trcSnapshotConfig.h.
+ *
+ * Read more at http://percepio.com/2016/10/05/rtos-tracing/
*
* Terms of Use
- * This software is copyright Percepio AB. The recorder library is free for
- * use together with Percepio products. You may distribute the recorder library
- * in its original form, including modifications in trcHardwarePort.c/.h
- * given that these modification are clearly marked as your own modifications
- * and documented in the initial comment section of these source files.
- * This software is the intellectual property of Percepio AB and may not be
- * sold or in other ways commercially redistributed without explicit written
- * permission by Percepio AB.
+ * This file is part of the trace recorder library (RECORDER), which is the
+ * intellectual property of Percepio AB (PERCEPIO) and provided under a
+ * license as follows.
+ * The RECORDER may be used free of charge for the purpose of recording data
+ * intended for analysis in PERCEPIO products. It may not be used or modified
+ * for other purposes without explicit permission from PERCEPIO.
+ * You may distribute the RECORDER in its original source code form, assuming
+ * this text (terms of use, disclaimer, copyright notice) is unchanged. You are
+ * allowed to distribute the RECORDER with minor modifications intended for
+ * configuration or porting of the RECORDER, e.g., to allow using it on a
+ * specific processor, processor family or with a specific communication
+ * interface. Any such modifications should be documented directly below
+ * this comment block.
*
* Disclaimer
- * The trace tool and recorder library is being delivered to you AS IS and
- * Percepio AB makes no warranty as to its use or performance. Percepio AB does
- * not and cannot warrant the performance or results you may obtain by using the
- * software or documentation. Percepio AB make no warranties, express or
- * implied, as to noninfringement of third party rights, merchantability, or
- * fitness for any particular purpose. In no event will Percepio AB, its
- * technology partners, or distributors be liable to you for any consequential,
- * incidental or special damages, including any lost profits or lost savings,
- * even if a representative of Percepio AB has been advised of the possibility
- * of such damages, or for any claim by any third party. Some jurisdictions do
- * not allow the exclusion or limitation of incidental, consequential or special
- * damages, or the exclusion of implied warranties or limitations on how long an
- * implied warranty may last, so the above limitations may not apply to you.
+ * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty
+ * as to its use or performance. PERCEPIO does not and cannot warrant the
+ * performance or results you may obtain by using the RECORDER or documentation.
+ * PERCEPIO make no warranties, express or implied, as to noninfringement of
+ * third party rights, merchantability, or fitness for any particular purpose.
+ * In no event will PERCEPIO, its technology partners, or distributors be liable
+ * to you for any consequential, incidental or special damages, including any
+ * lost profits or lost savings, even if a representative of PERCEPIO has been
+ * advised of the possibility of such damages, or for any claim by any third
+ * party. Some jurisdictions do not allow the exclusion or limitation of
+ * incidental, consequential or special damages, or the exclusion of implied
+ * warranties or limitations on how long an implied warranty may last, so the
+ * above limitations may not apply to you.
*
* Tabs are used for indent in this file (1 tab = 4 spaces)
*
- * Copyright Percepio AB, 2014.
+ * Copyright Percepio AB, 2016.
* www.percepio.com
******************************************************************************/
-#ifndef TRCCONFIG_H
-#define TRCCONFIG_H
-
-/******************************************************************************
- * SELECTED_PORT
- *
- * Macro that specifies what hardware port that should be used.
- * Available ports are:
- *
- * Port Name Code Official OS supported
- * PORT_APPLICATION_DEFINED -2 - -
- * PORT_NOT_SET -1 - -
- * PORT_HWIndependent 0 Yes Any
- * PORT_Win32 1 Yes FreeRTOS on Win32
- * PORT_Atmel_AT91SAM7 2 No Any
- * PORT_Atmel_UC3A0 3 No Any
- * PORT_ARM_CortexM 4 Yes Any
- * PORT_Renesas_RX600 5 Yes Any
- * PORT_Microchip_dsPIC_AND_PIC24 6 Yes Any
- * PORT_TEXAS_INSTRUMENTS_TMS570 7 No Any
- * PORT_TEXAS_INSTRUMENTS_MSP430 8 No Any
- * PORT_MICROCHIP_PIC32MX 9 Yes Any
- * PORT_XILINX_PPC405 10 No FreeRTOS
- * PORT_XILINX_PPC440 11 No FreeRTOS
- * PORT_XILINX_MICROBLAZE 12 No Any
- * PORT_NXP_LPC210X 13 No Any
- * PORT_MICROCHIP_PIC32MZ 14 Yes Any
- * PORT_ARM_CORTEX_A9 15 No Any
- *****************************************************************************/
-
-#ifndef WIN32
- // Set the port setting here!
- #define SELECTED_PORT PORT_ARM_CortexM
+#ifndef TRC_CONFIG_H
+#define TRC_CONFIG_H
- #if (SELECTED_PORT == PORT_NOT_SET)
- #error "You need to define SELECTED_PORT here!"
- #endif
-#else
- // For Win32 demo projects this is set automatically
- #define SELECTED_PORT PORT_Win32
+#ifdef __cplusplus
+extern "C" {
#endif
-/******************************************************************************
- * FREERTOS_VERSION
- *
- * Specify what version of FreeRTOS that is used. This is necessary compensate
- * for renamed symbols in the FreeRTOS kernel (does not build if incorrect).
- *
- * FREERTOS_VERSION_7_3_OR_7_4 (= 1) If using FreeRTOS v7.3.0 - v7.4.2
- * FREERTOS_VERSION_7_5_OR_7_6 (= 2) If using FreeRTOS v7.5.0 - v7.6.0
- * FREERTOS_VERSION_8_0_OR_LATER (= 3) If using FreeRTOS v8.0.0 or later
- *****************************************************************************/
-#define FREERTOS_VERSION FREERTOS_VERSION_8_0_OR_LATER
+#include "trcPortDefines.h"
/******************************************************************************
- * TRACE_RECORDER_STORE_MODE
+ * Include of processor header file
*
- * Macro which should be defined as one of:
- * - TRACE_STORE_MODE_RING_BUFFER
- * - TRACE_STORE_MODE_STOP_WHEN_FULL
- * Default is TRACE_STORE_MODE_RING_BUFFER.
- *
- * With TRACE_RECORDER_STORE_MODE set to TRACE_STORE_MODE_RING_BUFFER, the
- * events are stored in a ring buffer, i.e., where the oldest events are
- * overwritten when the buffer becomes full. This allows you to get the last
- * events leading up to an interesting state, e.g., an error, without having
- * to store the whole run since startup.
- *
- * When TRACE_RECORDER_STORE_MODE is TRACE_STORE_MODE_STOP_WHEN_FULL, the
- * recording is stopped when the buffer becomes full. This is useful for
- * recording events following a specific state, e.g., the startup sequence.
+ * Here you may need to include the header file for your processor. This is
+ * required at least for the ARM Cortex-M port, that uses the ARM CMSIS API.
+ * Try that in case of build problems. Otherwise, remove the #error line below.
*****************************************************************************/
-#define TRACE_RECORDER_STORE_MODE TRACE_STORE_MODE_RING_BUFFER
+//#error "Trace Recorder: Please include your processor's header file here and remove this line."
+#include "lpc18xx.h"
/*******************************************************************************
- * TRACE_SCHEDULING_ONLY
+ * Configuration Macro: TRC_CFG_HARDWARE_PORT
*
- * Macro which should be defined as an integer value.
+ * Specify what hardware port to use (i.e., the "timestamping driver").
*
- * If this setting is enabled (= 1), only scheduling events are recorded.
- * If disabled (= 0), all events are recorded.
+ * All ARM Cortex-M MCUs are supported by "TRC_HARDWARE_PORT_ARM_Cortex_M".
+ * This port uses the DWT cycle counter for Cortex-M3/M4/M7 devices, which is
+ * available on most such devices. In case your device don't have DWT support,
+ * you will get an error message opening the trace. In that case, you may
+ * force the recorder to use SysTick timestamping instead, using this define:
*
- * Users of FreeRTOS+Trace Free Edition only displays scheduling events, so this
- * option can be used to avoid storing unsupported events.
+ * #define TRC_CFG_ARM_CM_USE_SYSTICK
*
- * Default value is 0 (store all enabled events).
+ * For ARM Cortex-M0/M0+ devices, SysTick mode is used automatically.
*
+ * See trcHardwarePort.h for available ports and information on how to
+ * define your own port, if not already present.
******************************************************************************/
-#define TRACE_SCHEDULING_ONLY 0
+#define TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_ARM_Cortex_M
/*******************************************************************************
- * EVENT_BUFFER_SIZE
+ * Configuration Macro: TRC_CFG_RECORDER_MODE
*
- * Macro which should be defined as an integer value.
+ * Specify what recording mode to use. Snapshot means that the data is saved in
+ * an internal RAM buffer, for later upload. Streaming means that the data is
+ * transferred continuously to the host PC.
*
- * This defines the capacity of the event buffer, i.e., the number of records
- * it may store. Most events use one record (4 byte), although some events
- * require multiple 4-byte records. You should adjust this to the amount of RAM
- * available in the target system.
+ * For more information, see http://percepio.com/2016/10/05/rtos-tracing/
+ * and the Tracealyzer User Manual.
*
- * Default value is 1000, which means that 4000 bytes is allocated for the
- * event buffer.
+ * Values:
+ * TRC_RECORDER_MODE_SNAPSHOT
+ * TRC_RECORDER_MODE_STREAMING
******************************************************************************/
-#define EVENT_BUFFER_SIZE 1000
+#define TRC_CFG_RECORDER_MODE TRC_RECORDER_MODE_SNAPSHOT
/*******************************************************************************
- * NTask, NISR, NQueue, NSemaphore, NMutex
- *
- * A group of macros which should be defined as integer values, zero or larger.
+ * Configuration Macro: TRC_CFG_RECORDER_BUFFER_ALLOCATION
*
- * These define the capacity of the Object Property Table, i.e., the maximum
- * number of objects active at any given point, within each object class (e.g.,
- * task, queue, semaphore, ...).
+ * Specifies how the recorder buffer is allocated (also in case of streaming, in
+ * port using the recorder's internal temporary buffer)
*
- * If tasks or other other objects are deleted in your system, this
- * setting does not limit the total amount of objects created, only the number
- * of objects that have been successfully created but not yet deleted.
+ * Values:
+ * TRC_RECORDER_BUFFER_ALLOCATION_STATIC - Static allocation (internal)
+ * TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC - Malloc in vTraceEnable
+ * TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM - Use vTraceSetRecorderDataBuffer
*
- * Using too small values will cause vTraceError to be called, which stores an
- * error message in the trace that is shown when opening the trace file.
- *
- * It can be wise to start with large values for these constants,
- * unless you are very confident on these numbers. Then do a recording and
- * check the actual usage by selecting View menu -> Trace Details ->
- * Resource Usage -> Object Table.
+ * Static and dynamic mode does the allocation for you, either in compile time
+ * (static) or in runtime (malloc).
+ * The custom mode allows you to control how and where the allocation is made,
+ * for details see TRC_ALLOC_CUSTOM_BUFFER and vTraceSetRecorderDataBuffer().
******************************************************************************/
-#define NTask 15
-#define NISR 4
-#define NQueue 10
-#define NSemaphore 10
-#define NMutex 5
-#define NTimer 10
-#define NEventGroup 1
+#define TRC_CFG_RECORDER_BUFFER_ALLOCATION TRC_RECORDER_BUFFER_ALLOCATION_STATIC
/******************************************************************************
- * INCLUDE_MEMMANG_EVENTS
- *
- * Macro which should be defined as either zero (0) or one (1).
+ * TRC_CFG_FREERTOS_VERSION
*
- * This controls if malloc and free calls should be traced. Set this to zero to
- * exclude malloc/free calls, or one (1) to include such events in the trace.
+ * Specify what version of FreeRTOS that is used (don't change unless using the
+ * trace recorder library with an older version of FreeRTOS).
*
- * Default value is 1.
+ * TRC_FREERTOS_VERSION_7_3_OR_7_4 If using FreeRTOS v7.3.0 - v7.4.2
+ * TRC_FREERTOS_VERSION_7_5_OR_7_6 If using FreeRTOS v7.5.0 - v7.6.0
+ * TRC_FREERTOS_VERSION_8_X If using FreeRTOS v8.X.X
+ * TRC_FREERTOS_VERSION_9_X If using FreeRTOS v9.X.X
*****************************************************************************/
-#define INCLUDE_MEMMANG_EVENTS 1
+#define TRC_CFG_FREERTOS_VERSION TRC_FREERTOS_VERSION_9_X
/******************************************************************************
- * INCLUDE_USER_EVENTS
+ * TRC_CFG_MAX_ISR_NESTING
*
- * Macro which should be defined as either zero (0) or one (1).
+ * Defines how many levels of interrupt nesting the recorder can handle, in
+ * case multiple ISRs are traced and ISR nesting is possible. If this
+ * is exceeded, the particular ISR will not be traced and the recorder then
+ * logs an error message. This setting is used to allocate an internal stack
+ * for keeping track of the previous execution context (4 byte per entry).
*
- * If this is zero (0) the code for creating User Events is excluded to
- * reduce code size. User Events are application-generated events, like
- * "printf" but for the trace log instead of console output. User Events are
- * much faster than a printf and can therefore be used in timing critical code.
- * See vTraceUserEvent() and vTracePrintF() in trcUser.h
+ * This value must be a non-zero positive constant, at least 1.
*
- * Default value is 1.
- *
- * Note that User Events are only displayed in Professional Edition.
+ * Default value: 8
*****************************************************************************/
-#define INCLUDE_USER_EVENTS 0
+#define TRC_CFG_MAX_ISR_NESTING 8
-/*****************************************************************************
- * INCLUDE_ISR_TRACING
- *
- * Macro which should be defined as either zero (0) or one (1).
- *
- * If this is zero (0), the code for recording Interrupt Service Routines is
- * excluded to reduce code size.
- *
- * Default value is 1.
- *
- * Note, if the kernel has no central interrupt dispatcher, recording ISRs
- * require that you insert calls to vTraceStoreISRBegin and vTraceStoreISREnd
- * in your interrupt handlers.
- *****************************************************************************/
-#define INCLUDE_ISR_TRACING 1
-
-/*****************************************************************************
- * INCLUDE_READY_EVENTS
- *
- * Macro which should be defined as either zero (0) or one (1).
- *
- * If one (1), events are recorded when tasks enter scheduling state "ready".
- * This uses a lot of space in the event buffer, so excluding "ready events"
- * will allow for longer traces. Including ready events however allows for
- * showing the initial pending time before tasks enter the execution state, and
- * for presenting accurate response times.
- *
- * Default value is 1.
- *****************************************************************************/
-#define INCLUDE_READY_EVENTS 1
-
-/*****************************************************************************
- * INCLUDE_NEW_TIME_EVENTS
- *
- * Macro which should be defined as either zero (0) or one (1).
- *
- * If this is zero (1), events will be generated whenever the OS clock is
- * increased.
- *
- * Default value is 0.
- *****************************************************************************/
-#define INCLUDE_NEW_TIME_EVENTS 0
-
-/******************************************************************************
- * INCLUDE_FLOAT_SUPPORT
- *
- * Macro which should be defined as either zero (0) or one (1).
- *
- * If this is zero (0), all references to floating point values are removed,
- * in case floating point values are not supported by the platform used.
- * Floating point values are only used in vTracePrintF and its subroutines, to
- * store float (%f) or double (%lf) arguments.
- *
- * vTracePrintF can be used with integer and string arguments in either case.
- *
- * Default value is 1.
- *****************************************************************************/
-#define INCLUDE_FLOAT_SUPPORT 0
-
-/******************************************************************************
- * INCLUDE_OBJECT_DELETE
- *
- * Macro which should be defined as either zero (0) or one (1).
- *
- * This must be enabled (1) if tasks, queues or other
- * traced kernel objects are deleted at runtime. If no deletes are made, this
- * can be set to 0 in order to exclude the delete-handling code.
- *
- * Default value is 1.
- *****************************************************************************/
-#define INCLUDE_OBJECT_DELETE 1
-
-/*******************************************************************************
- * SYMBOL_TABLE_SIZE
- *
- * Macro which should be defined as an integer value.
- *
- * This defines the capacity of the symbol table, in bytes. This symbol table
- * stores User Events labels and names of deleted tasks, queues, or other kernel
- * objects. If you don't use User Events or delete any kernel
- * objects you set this to a very low value. The minimum recommended value is 4.
- * A size of zero (0) is not allowed since a zero-sized array may result in a
- * 32-bit pointer, i.e., using 4 bytes rather than 0.
- *
- * Default value is 800.
- ******************************************************************************/
-#define SYMBOL_TABLE_SIZE 5000
-
-#if (SYMBOL_TABLE_SIZE == 0)
-#error "SYMBOL_TABLE_SIZE may not be zero!"
+/* Specific configuration, depending on Streaming/Snapshot mode */
+#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
+#include "trcSnapshotConfig.h"
+#elif (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
+#include "trcStreamingConfig.h"
#endif
-/******************************************************************************
- * NameLenTask, NameLenQueue, ...
- *
- * Macros that specify the maximum lengths (number of characters) for names of
- * kernel objects, such as tasks and queues. If longer names are used, they will
- * be truncated when stored in the recorder.
- *****************************************************************************/
-#define NameLenTask 15
-#define NameLenISR 15
-#define NameLenQueue 15
-#define NameLenSemaphore 15
-#define NameLenMutex 15
-#define NameLenTimer 15
-#define NameLenEventGroup 15
-
-/******************************************************************************
- * TRACE_DATA_ALLOCATION
- *
- * This defines how to allocate the recorder data structure, i.e., using a
- * static declaration or using a dynamic allocation in runtime (malloc).
- *
- * Should be one of these two options:
- * - TRACE_DATA_ALLOCATION_STATIC (default)
- * - TRACE_DATA_ALLOCATION_DYNAMIC
- *
- * Using static allocation has the benefits of compile-time errors if the buffer
- * is too large (too large constants in trcConfig.h) and no need to call the
- * initialization routine (xTraceInitTraceData).
- *
- * Using dynamic allocation may give more flexibility in some cases.
- *****************************************************************************/
-#define TRACE_DATA_ALLOCATION TRACE_DATA_ALLOCATION_STATIC
-
-
-
-/******************************************************************************
- *** ADVANCED SETTINGS ********************************************************
- ******************************************************************************
- * The remaining settings are not necessary to modify but allows for optimizing
- * the recorder setup for your specific needs, e.g., to exclude events that you
- * are not interested in, in order to get longer traces.
- *****************************************************************************/
-
-/******************************************************************************
-* HEAP_SIZE_BELOW_16M
-*
-* An integer constant that can be used to reduce the buffer usage of memory
-* allocation events (malloc/free). This value should be 1 if the heap size is
-* below 16 MB (2^24 byte), and you can live with reported addresses showing the
-* lower 24 bits only. If 0, you get the full 32-bit addresses.
-*
-* Default value is 0.
-******************************************************************************/
-#define HEAP_SIZE_BELOW_16M 0
-
-/******************************************************************************
- * USE_LINKER_PRAGMA
- *
- * Macro which should be defined as an integer value, default is 0.
- *
- * If this is 1, the header file "recorderdata_linker_pragma.h" is included just
- * before the declaration of RecorderData (in trcBase.c), i.e., the trace data
- * structure. This allows the user to specify a pragma with linker options.
- *
- * Example (for IAR Embedded Workbench and NXP LPC17xx):
- * #pragma location="AHB_RAM_MEMORY"
- *
- * This example instructs the IAR linker to place RecorderData in another RAM
- * bank, the AHB RAM. This can also be used for other compilers with a similar
- * pragmas for linker options.
- *
- * Note that this only applies if using static allocation, see below.
- ******************************************************************************/
-#define USE_LINKER_PRAGMA 0
-
-/******************************************************************************
- * USE_IMPLICIT_IFE_RULES
- *
- * Macro which should be defined as either zero (0) or one (1).
- * Default is 1.
- *
- * Tracealyzer groups the events into actor instances, based on context-switches
- * and a definition of "Instance Finish Events", or IFEs. These are kernel calls
- * considered to be the last event in a task instance. Some kernel calls are
- * considered IFEs by default (e.g., delay functions), but it is also possible
- * to specify this individually for each task (see vTraceTaskInstanceFinish).
- *
- * If USE_IMPLICIT_IFE_RULES is one (1), the default IFEs will be enabled, which
- * gives a "typical" grouping of events into instances. You can combine this
- * with calls to vTraceTaskInstanceFinish for specific tasks.
- *
- * If USE_IMPLICIT_IFE_RULES is zero (0), the implicit IFEs are disabled and all
- * events withing each task is then shown as a single instance, unless you call
- * vTraceTaskInstanceFinish() at suitable locations to mark the IFEs.
- *****************************************************************************/
-#define USE_IMPLICIT_IFE_RULES 1
-
-/******************************************************************************
- * USE_16BIT_OBJECT_HANDLES
- *
- * Macro which should be defined as either zero (0) or one (1).
- *
- * If set to 0 (zero), the recorder uses 8-bit handles to identify kernel
- * objects such as tasks and queues. This limits the supported number of
- * concurrently active objects to 255 of each type (object class).
- *
- * If set to 1 (one), the recorder uses 16-bit handles to identify kernel
- * objects such as tasks and queues. This limits the supported number of
- * concurrent objects to 65535 of each type (object class). However, since the
- * object property table is limited to 64 KB, the practical limit is about
- * 3000 objects in total.
- *
- * Default is 0.
- *
- * NOTE: An object with handle above 255 will use an extra 4-byte record in
- * the event buffer whenever referenced. Moreover, some internal tables in the
- * recorder gets larger when using 16-bit handles. The additional RAM usage is
- * 5-10 byte plus 1 byte per kernel object i.e., task, queue, mutex, etc.
- *****************************************************************************/
-#define USE_16BIT_OBJECT_HANDLES 0
-
-/******************************************************************************
- * USE_TRACE_ASSERT
- *
- * Macro which should be defined as either zero (0) or one (1).
- * Default is 1.
- *
- * If this is one (1), the TRACE_ASSERT macro will verify that a condition is
- * true. If the condition is false, vTraceError() will be called.
- * This is used on several places in the recorder code for sanity checks on
- * parameters. Can be switched off to reduce CPU usage of the tracing.
- *****************************************************************************/
-#define USE_TRACE_ASSERT 1
-
-/*******************************************************************************
- * USE_SEPARATE_USER_EVENT_BUFFER
- *
- * Macro which should be defined as an integer value.
- * Default is zero (0).
- *
- * This enables and disables the use of the separate user event buffer. Using
- * this separate buffer has the benefit of not overwriting the user events with
- * kernel events (usually generated at a much higher rate), i.e., when using
- * ring-buffer mode.
- *
- * Note: When using the separate user event buffer, you may get an artificial
- * task instance named "Unknown actor". This is added as a placeholder when the
- * user event history is longer than the task scheduling history.
- ******************************************************************************/
-#define USE_SEPARATE_USER_EVENT_BUFFER 0
-
-/*******************************************************************************
- * USER_EVENT_BUFFER_SIZE
- *
- * Macro which should be defined as an integer value.
- *
- * This defines the capacity of the user event buffer, in number of slots.
- * A single user event can use between 1 and X slots, depending on the data.
- *
- * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1.
- ******************************************************************************/
-#define USER_EVENT_BUFFER_SIZE 10
-
-/*******************************************************************************
- * USER_EVENT_CHANNELS
- *
- * Macro which should be defined as an integer value.
- *
- * This defines the number of allowed user event channels.
- *
- * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1.
- ******************************************************************************/
-#define CHANNEL_FORMAT_PAIRS 32
-
+#ifdef __cplusplus
+}
#endif
+#endif /* _TRC_CONFIG_H */
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/trcSnapshotConfig.h b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/trcSnapshotConfig.h
new file mode 100644
index 000000000..e84a40b0c
--- /dev/null
+++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/trcSnapshotConfig.h
@@ -0,0 +1,472 @@
+/*******************************************************************************
+ * Trace Recorder Library for Tracealyzer v3.1.2
+ * Percepio AB, www.percepio.com
+ *
+ * trcSnapshotConfig.h
+ *
+ * Configuration parameters for trace recorder library in snapshot mode.
+ * Read more at http://percepio.com/2016/10/05/rtos-tracing/
+ *
+ * Terms of Use
+ * This file is part of the trace recorder library (RECORDER), which is the
+ * intellectual property of Percepio AB (PERCEPIO) and provided under a
+ * license as follows.
+ * The RECORDER may be used free of charge for the purpose of recording data
+ * intended for analysis in PERCEPIO products. It may not be used or modified
+ * for other purposes without explicit permission from PERCEPIO.
+ * You may distribute the RECORDER in its original source code form, assuming
+ * this text (terms of use, disclaimer, copyright notice) is unchanged. You are
+ * allowed to distribute the RECORDER with minor modifications intended for
+ * configuration or porting of the RECORDER, e.g., to allow using it on a
+ * specific processor, processor family or with a specific communication
+ * interface. Any such modifications should be documented directly below
+ * this comment block.
+ *
+ * Disclaimer
+ * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty
+ * as to its use or performance. PERCEPIO does not and cannot warrant the
+ * performance or results you may obtain by using the RECORDER or documentation.
+ * PERCEPIO make no warranties, express or implied, as to noninfringement of
+ * third party rights, merchantability, or fitness for any particular purpose.
+ * In no event will PERCEPIO, its technology partners, or distributors be liable
+ * to you for any consequential, incidental or special damages, including any
+ * lost profits or lost savings, even if a representative of PERCEPIO has been
+ * advised of the possibility of such damages, or for any claim by any third
+ * party. Some jurisdictions do not allow the exclusion or limitation of
+ * incidental, consequential or special damages, or the exclusion of implied
+ * warranties or limitations on how long an implied warranty may last, so the
+ * above limitations may not apply to you.
+ *
+ * Tabs are used for indent in this file (1 tab = 4 spaces)
+ *
+ * Copyright Percepio AB, 2017.
+ * www.percepio.com
+ ******************************************************************************/
+
+#ifndef TRC_SNAPSHOT_CONFIG_H
+#define TRC_SNAPSHOT_CONFIG_H
+
+#define TRC_SNAPSHOT_MODE_RING_BUFFER (0x01)
+#define TRC_SNAPSHOT_MODE_STOP_WHEN_FULL (0x02)
+
+/******************************************************************************
+ * TRC_CFG_SNAPSHOT_MODE
+ *
+ * Macro which should be defined as one of:
+ * - TRC_SNAPSHOT_MODE_RING_BUFFER
+ * - TRC_SNAPSHOT_MODE_STOP_WHEN_FULL
+ * Default is TRC_SNAPSHOT_MODE_RING_BUFFER.
+ *
+ * With TRC_CFG_SNAPSHOT_MODE set to TRC_SNAPSHOT_MODE_RING_BUFFER, the
+ * events are stored in a ring buffer, i.e., where the oldest events are
+ * overwritten when the buffer becomes full. This allows you to get the last
+ * events leading up to an interesting state, e.g., an error, without having
+ * to store the whole run since startup.
+ *
+ * When TRC_CFG_SNAPSHOT_MODE is TRC_SNAPSHOT_MODE_STOP_WHEN_FULL, the
+ * recording is stopped when the buffer becomes full. This is useful for
+ * recording events following a specific state, e.g., the startup sequence.
+ *****************************************************************************/
+#define TRC_CFG_SNAPSHOT_MODE TRC_SNAPSHOT_MODE_RING_BUFFER
+
+/*******************************************************************************
+ * TRC_CFG_SCHEDULING_ONLY
+ *
+ * Macro which should be defined as an integer value.
+ *
+ * If this setting is enabled (= 1), only scheduling events are recorded.
+ * If disabled (= 0), all events are recorded.
+ *
+ * For users of Tracealyzer Free Edition, that only displays scheduling events, this
+ * option can be used to avoid storing other events.
+ *
+ * Default value is 0 (store all enabled events).
+ *
+ ******************************************************************************/
+#define TRC_CFG_SCHEDULING_ONLY 0
+
+/*******************************************************************************
+ * TRC_CFG_EVENT_BUFFER_SIZE
+ *
+ * Macro which should be defined as an integer value.
+ *
+ * This defines the capacity of the event buffer, i.e., the number of records
+ * it may store. Most events use one record (4 byte), although some events
+ * require multiple 4-byte records. You should adjust this to the amount of RAM
+ * available in the target system.
+ *
+ * Default value is 1000, which means that 4000 bytes is allocated for the
+ * event buffer.
+ ******************************************************************************/
+#define TRC_CFG_EVENT_BUFFER_SIZE 1000
+
+/*******************************************************************************
+ * TRC_CFG_NTASK, TRC_CFG_NISR, TRC_CFG_NQUEUE, TRC_CFG_NSEMAPHORE...
+ *
+ * A group of macros which should be defined as integer values, zero or larger.
+ *
+ * These define the capacity of the Object Property Table, i.e., the maximum
+ * number of objects active at any given point, within each object class (e.g.,
+ * task, queue, semaphore, ...).
+ *
+ * If tasks or other objects are deleted in your system, this
+ * setting does not limit the total amount of objects created, only the number
+ * of objects that have been successfully created but not yet deleted.
+ *
+ * Using too small values will cause vTraceError to be called, which stores an
+ * error message in the trace that is shown when opening the trace file. The
+ * error message can also be retrieved using xTraceGetLastError.
+ *
+ * It can be wise to start with large values for these constants,
+ * unless you are very confident on these numbers. Then do a recording and
+ * check the actual usage by selecting View menu -> Trace Details ->
+ * Resource Usage -> Object Table.
+ ******************************************************************************/
+#define TRC_CFG_NTASK 15
+#define TRC_CFG_NISR 4
+#define TRC_CFG_NQUEUE 10
+#define TRC_CFG_NSEMAPHORE 10
+#define TRC_CFG_NMUTEX 5
+#define TRC_CFG_NTIMER 10
+#define TRC_CFG_NEVENTGROUP 1
+
+/******************************************************************************
+ * TRC_CFG_INCLUDE_MEMMANG_EVENTS
+ *
+ * Macro which should be defined as either zero (0) or one (1).
+ *
+ * This controls if malloc and free calls should be traced. Set this to zero (0)
+ * to exclude malloc/free calls, or one (1) to include such events in the trace.
+ *
+ * Default value is 1.
+ *****************************************************************************/
+#define TRC_CFG_INCLUDE_MEMMANG_EVENTS 1
+
+/******************************************************************************
+ * TRC_CFG_INCLUDE_USER_EVENTS
+ *
+ * Macro which should be defined as either zero (0) or one (1).
+ *
+ * If this is zero (0) the code for creating User Events is excluded to
+ * reduce code size. User Events are application-generated events, like
+ * "printf" but for the trace log and the formatting is done offline, by the
+ * Tracealyzer visualization tool. User Events are much faster than a printf
+ * and can therefore be used in timing critical code.
+ *
+ * Default value is 1.
+ *****************************************************************************/
+#define TRC_CFG_INCLUDE_USER_EVENTS 0
+
+/*****************************************************************************
+ * TRC_CFG_INCLUDE_ISR_TRACING
+ *
+ * Macro which should be defined as either zero (0) or one (1).
+ *
+ * If this is zero (0), the code for recording Interrupt Service Routines is
+ * excluded, in order to reduce code size.
+ *
+ * Default value is 1.
+ *
+ * Note: tracing ISRs requires that you insert calls to vTraceStoreISRBegin
+ * and vTraceStoreISREnd in your interrupt handlers.
+ *****************************************************************************/
+#define TRC_CFG_INCLUDE_ISR_TRACING 1
+
+/*****************************************************************************
+ * TRC_CFG_INCLUDE_READY_EVENTS
+ *
+ * Macro which should be defined as either zero (0) or one (1).
+ *
+ * If one (1), events are recorded when tasks enter scheduling state "ready".
+ * This allows Tracealyzer to show the initial pending time before tasks enter
+ * the execution state, and present accurate response times.
+ * If zero (0), "ready events" are not created, which allows for recording
+ * longer traces in the same amount of RAM.
+ *
+ * Default value is 1.
+ *****************************************************************************/
+#define TRC_CFG_INCLUDE_READY_EVENTS 1
+
+/*****************************************************************************
+ * TRC_CFG_INCLUDE_OSTICK_EVENTS
+ *
+ * Macro which should be defined as either zero (0) or one (1).
+ *
+ * If this is one (1), events will be generated whenever the OS clock is
+ * increased. If zero (0), OS tick events are not generated, which allows for
+ * recording longer traces in the same amount of RAM.
+ *
+ * Default value is 0.
+ *****************************************************************************/
+#define TRC_CFG_INCLUDE_OSTICK_EVENTS 1
+
+/******************************************************************************
+ * TRC_CFG_INCLUDE_FLOAT_SUPPORT
+ *
+ * Macro which should be defined as either zero (0) or one (1).
+ *
+ * If this is zero (0), the support for logging floating point values in
+ * vTracePrintF is stripped out, in case floating point values are not used or
+ * supported by the platform used.
+ *
+ * Floating point values are only used in vTracePrintF and its subroutines, to
+ * allow for storing float (%f) or double (%lf) arguments.
+ *
+ * vTracePrintF can be used with integer and string arguments in either case.
+ *
+ * Default value is 0.
+ *****************************************************************************/
+#define TRC_CFG_INCLUDE_FLOAT_SUPPORT 0
+
+/******************************************************************************
+ * TRC_CFG_INCLUDE_OBJECT_DELETE
+ *
+ * Macro which should be defined as either zero (0) or one (1).
+ *
+ * This must be enabled (1) if tasks, queues or other
+ * traced kernel objects are deleted at runtime. If no deletes are made, this
+ * can be set to 0 in order to exclude the delete-handling code.
+ *
+ * Default value is 1.
+ *****************************************************************************/
+#define TRC_CFG_INCLUDE_OBJECT_DELETE 1
+
+/*******************************************************************************
+ * TRC_CFG_SYMBOL_TABLE_SIZE
+ *
+ * Macro which should be defined as an integer value.
+ *
+ * This defines the capacity of the symbol table, in bytes. This symbol table
+ * stores User Events labels and names of deleted tasks, queues, or other kernel
+ * objects. If you don't use User Events or delete any kernel
+ * objects you set this to a very low value. The minimum recommended value is 4.
+ * A size of zero (0) is not allowed since a zero-sized array may result in a
+ * 32-bit pointer, i.e., using 4 bytes rather than 0.
+ *
+ * Default value is 800.
+ ******************************************************************************/
+#define TRC_CFG_SYMBOL_TABLE_SIZE 5000
+
+#if (TRC_CFG_SYMBOL_TABLE_SIZE == 0)
+#error "TRC_CFG_SYMBOL_TABLE_SIZE may not be zero!"
+#endif
+
+/******************************************************************************
+ * TRC_CFG_NAME_LEN_TASK, TRC_CFG_NAME_LEN_QUEUE, ...
+ *
+ * Macros that specify the maximum lengths (number of characters) for names of
+ * kernel objects, such as tasks and queues. If longer names are used, they will
+ * be truncated when stored in the recorder.
+ *****************************************************************************/
+#define TRC_CFG_NAME_LEN_TASK 15
+#define TRC_CFG_NAME_LEN_ISR 15
+#define TRC_CFG_NAME_LEN_QUEUE 15
+#define TRC_CFG_NAME_LEN_SEMAPHORE 15
+#define TRC_CFG_NAME_LEN_MUTEX 15
+#define TRC_CFG_NAME_LEN_TIMER 15
+#define TRC_CFG_NAME_LEN_EVENTGROUP 15
+
+/******************************************************************************
+ *** ADVANCED SETTINGS ********************************************************
+ ******************************************************************************
+ * The remaining settings are not necessary to modify but allows for optimizing
+ * the recorder setup for your specific needs, e.g., to exclude events that you
+ * are not interested in, in order to get longer traces.
+ *****************************************************************************/
+
+/******************************************************************************
+* TRC_CFG_HEAP_SIZE_BELOW_16M
+*
+* An integer constant that can be used to reduce the buffer usage of memory
+* allocation events (malloc/free). This value should be 1 if the heap size is
+* below 16 MB (2^24 byte), and you can live with reported addresses showing the
+* lower 24 bits only. If 0, you get the full 32-bit addresses.
+*
+* Default value is 0.
+******************************************************************************/
+#define TRC_CFG_HEAP_SIZE_BELOW_16M 0
+
+/******************************************************************************
+ * TRC_CFG_USE_IMPLICIT_IFE_RULES
+ *
+ * Macro which should be defined as either zero (0) or one (1).
+ * Default is 1.
+ *
+ * Tracealyzer groups the events into "instances" based on Instance Finish
+ * Events (IFEs), produced either by default rules or calls to the recorder
+ * functions vTraceInstanceFinishedNow and vTraceInstanceFinishedNext.
+ *
+ * If TRC_CFG_USE_IMPLICIT_IFE_RULES is one (1), the default IFE rules is
+ * used, resulting in a "typical" grouping of events into instances.
+ * If these rules don't give appropriate instances in your case, you can
+ * override the default rules using vTraceInstanceFinishedNow/Next for one
+ * or several tasks. The default IFE rules are then disabled for those tasks.
+ *
+ * If TRC_CFG_USE_IMPLICIT_IFE_RULES is zero (0), the implicit IFE rules are
+ * disabled globally. You must then call vTraceInstanceFinishedNow or
+ * vTraceInstanceFinishedNext to manually group the events into instances,
+ * otherwise the tasks will appear a single long instance.
+ *
+ * The default IFE rules count the following events as "instance finished":
+ * - Task delay, delay until
+ * - Task suspend
+ * - Blocking on "input" operations, i.e., when the task is waiting for the
+ * next a message/signal/event. But only if this event is blocking.
+ *
+ * For details, see trcSnapshotKernelPort.h and look for references to the
+ * macro trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED.
+ *****************************************************************************/
+#define TRC_CFG_USE_IMPLICIT_IFE_RULES 1
+
+/******************************************************************************
+ * TRC_CFG_USE_16BIT_OBJECT_HANDLES
+ *
+ * Macro which should be defined as either zero (0) or one (1).
+ *
+ * If set to 0 (zero), the recorder uses 8-bit handles to identify kernel
+ * objects such as tasks and queues. This limits the supported number of
+ * concurrently active objects to 255 of each type (tasks, queues, mutexes,
+ * etc.) Note: 255, not 256, since handle 0 is reserved.
+ *
+ * If set to 1 (one), the recorder uses 16-bit handles to identify kernel
+ * objects such as tasks and queues. This limits the supported number of
+ * concurrent objects to 65535 of each type (object class). However, since the
+ * object property table is limited to 64 KB, the practical limit is about
+ * 3000 objects in total.
+ *
+ * Default is 0 (8-bit handles)
+ *
+ * NOTE: An object with handle above 255 will use an extra 4-byte record in
+ * the event buffer whenever the object is referenced. Moreover, some internal
+ * tables in the recorder gets slightly larger when using 16-bit handles.
+ *****************************************************************************/
+#define TRC_CFG_USE_16BIT_OBJECT_HANDLES 0
+
+/******************************************************************************
+ * TRC_CFG_USE_TRACE_ASSERT
+ *
+ * Macro which should be defined as either zero (0) or one (1).
+ * Default is 1.
+ *
+ * If this is one (1), the TRACE_ASSERT macro (used at various locations in the
+ * trace recorder) will verify that a relevant condition is true.
+ * If the condition is false, prvTraceError() will be called, which stops the
+ * recording and stores an error message that is displayed when opening the
+ * trace in Tracealyzer.
+ *
+ * This is used on several places in the recorder code for sanity checks on
+ * parameters. Can be switched off to reduce the footprint of the tracing, but
+ * we recommend to have it enabled initially.
+ *****************************************************************************/
+#define TRC_CFG_USE_TRACE_ASSERT 1
+
+/*******************************************************************************
+ * TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER
+ *
+ * Macro which should be defined as an integer value.
+ *
+ * Set TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER to 1 to enable the
+ * separate user event buffer (UB).
+ * In this mode, user events are stored separately from other events,
+ * e.g., RTOS events. Thereby you can get a much longer history of
+ * user events as they don't need to share the buffer space with more
+ * frequent events.
+ *
+ * The UB is typically used with the snapshot ring-buffer mode, so the
+ * recording can continue when the main buffer gets full. And since the
+ * main buffer then overwrites the earliest events, Tracealyzer displays
+ * "Unknown Actor" instead of task scheduling for periods with UB data only.
+ *
+ * In UB mode, user events are structured as UB channels, which contains
+ * a channel name and a default format string. Register a UB channel using
+ * xTraceRegisterUBChannel.
+ *
+ * Events and data arguments are written using vTraceUBEvent and
+ * vTraceUBData. They are designed to provide efficient logging of
+ * repeating events, using the same format string within each channel.
+ *
+ * Examples:
+ *
+ * traceString chn1 = xTraceRegisterString("Channel 1");
+ * traceString fmt1 = xTraceRegisterString("Event!");
+ * traceUBChannel UBCh1 = xTraceRegisterUBChannel(chn1, fmt1);
+ *
+ * traceString chn2 = xTraceRegisterString("Channel 2");
+ * traceString fmt2 = xTraceRegisterString("X: %d, Y: %d");
+ * traceUBChannel UBCh2 = xTraceRegisterUBChannel(chn2, fmt2);
+ *
+ * // Result in "[Channel 1] Event!"
+ * vTraceUBEvent(UBCh1);
+ *
+ * // Result in "[Channel 2] X: 23, Y: 19"
+ * vTraceUBData(UBCh2, 23, 19);
+ *
+ * You can also use the other user event functions, like vTracePrintF.
+ * as they are then rerouted to the UB instead of the main event buffer.
+ * vTracePrintF then looks up the correct UB channel based on the
+ * provided channel name and format string, or creates a new UB channel
+ * if no match is found. The format string should therefore not contain
+ * "random" messages but mainly format specifiers. Random strings should
+ * be stored using %s and with the string as an argument.
+ *
+ * // Creates a new UB channel ("Channel 2", "%Z: %d")
+ * vTracePrintF(chn2, "%Z: %d", value1);
+ *
+ * // Finds the existing UB channel
+ * vTracePrintF(chn2, "%Z: %d", value2);
+
+ ******************************************************************************/
+#define TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER 0
+
+/*******************************************************************************
+ * TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE
+ *
+ * Macro which should be defined as an integer value.
+ *
+ * This defines the capacity of the user event buffer (UB), in number of slots.
+ * A single user event can use multiple slots, depending on the arguments.
+ *
+ * Only applicable if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is 1.
+ ******************************************************************************/
+#define TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE 10
+
+/*******************************************************************************
+ * TRC_CFG_UB_CHANNELS
+ *
+ * Macro which should be defined as an integer value.
+ *
+ * This defines the number of User Event Buffer Channels (UB channels).
+ * These are used to structure the events when using the separate user
+ * event buffer, and contains both a User Event Channel (the name) and
+ * a default format string for the channel.
+ *
+ * Only applicable if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is 1.
+ ******************************************************************************/
+#define TRC_CFG_UB_CHANNELS 32
+
+/*******************************************************************************
+ * TRC_CFG_ISR_TAILCHAINING_THRESHOLD
+ *
+ * Macro which should be defined as an integer value.
+ *
+ * If tracing multiple ISRs, this setting allows for accurate display of the
+ * context-switching also in cases when the ISRs execute in direct sequence.
+ *
+ * vTraceStoreISREnd normally assumes that the ISR returns to the previous
+ * context, i.e., a task or a preempted ISR. But if another traced ISR
+ * executes in direct sequence, Tracealyzer may incorrectly display a minimal
+ * fragment of the previous context in between the ISRs.
+ *
+ * By using TRC_CFG_ISR_TAILCHAINING_THRESHOLD you can avoid this. This is
+ * however a threshold value that must be measured for your specific setup.
+ * See http://percepio.com/2014/03/21/isr_tailchaining_threshold/
+ *
+ * The default setting is 0, meaning "disabled" and that you may get an
+ * extra fragments of the previous context in between tail-chained ISRs.
+ *
+ * Note: This setting has separate definitions in trcSnapshotConfig.h and
+ * trcStreamingConfig.h, since it is affected by the recorder mode.
+ ******************************************************************************/
+#define TRC_CFG_ISR_TAILCHAINING_THRESHOLD 0
+
+#endif /*TRC_SNAPSHOT_CONFIG_H*/
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c
new file mode 100644
index 000000000..5f2ff2559
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c
@@ -0,0 +1,682 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.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_DHCP.h"
+#if( ipconfigUSE_LLMNR == 1 )
+ #include "FreeRTOS_DNS.h"
+#endif /* ipconfigUSE_LLMNR */
+#include "NetworkInterface.h"
+#include "NetworkBufferManagement.h"
+
+
+/* When the age of an entry in the ARP table reaches this value (it counts down
+to zero, so this is an old entry) an ARP request will be sent to see if the
+entry is still valid and can therefore be refreshed. */
+#define arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST ( 3 )
+
+/* The time between gratuitous ARPs. */
+#ifndef arpGRATUITOUS_ARP_PERIOD
+ #define arpGRATUITOUS_ARP_PERIOD ( pdMS_TO_TICKS( 20000 ) )
+#endif
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Lookup an MAC address in the ARP cache from the IP address.
+ */
+static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress );
+
+/*-----------------------------------------------------------*/
+
+/* The ARP cache. */
+static ARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];
+
+/* The time at which the last gratuitous ARP was sent. Gratuitous ARPs are used
+to ensure ARP tables are up to date and to detect IP address conflicts. */
+static TickType_t xLastGratuitousARPTime = ( TickType_t ) 0;
+
+/*
+ * IP-clash detection is currently only used internally. When DHCP doesn't respond, the
+ * driver can try out a random LinkLayer IP address (169.254.x.x). It will send out a
+ * gratuitos ARP message and, after a period of time, check the variables here below:
+ */
+#if( ipconfigARP_USE_CLASH_DETECTION != 0 )
+ /* Becomes non-zero if another device responded to a gratuitos ARP message. */
+ BaseType_t xARPHadIPClash;
+ /* MAC-address of the other device containing the same IP-address. */
+ MACAddress_t xARPClashMacAddress;
+#endif /* ipconfigARP_USE_CLASH_DETECTION */
+
+/* Part of the Ethernet and ARP headers are always constant when sending an IPv4
+ARP packet. This array defines the constant parts, allowing this part of the
+packet to be filled in using a simple memcpy() instead of individual writes. */
+static const uint8_t xDefaultPartARPPacketHeader[] =
+{
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Ethernet destination address. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source address. */
+ 0x08, 0x06, /* Ethernet frame type (ipARP_FRAME_TYPE). */
+ 0x00, 0x01, /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */
+ 0x08, 0x00, /* usProtocolType. */
+ ipMAC_ADDRESS_LENGTH_BYTES, /* ucHardwareAddressLength. */
+ ipIP_ADDRESS_LENGTH_BYTES, /* ucProtocolAddressLength. */
+ 0x00, 0x01, /* usOperation (ipARP_REQUEST). */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* xSenderHardwareAddress. */
+ 0x00, 0x00, 0x00, 0x00, /* ulSenderProtocolAddress. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* xTargetHardwareAddress. */
+};
+
+/*-----------------------------------------------------------*/
+
+eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame )
+{
+eFrameProcessingResult_t eReturn = eReleaseBuffer;
+ARPHeader_t *pxARPHeader;
+uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress;
+
+ pxARPHeader = &( pxARPFrame->xARPHeader );
+
+ /* The field ulSenderProtocolAddress is badly aligned, copy byte-by-byte. */
+ memcpy( ( void *)&( ulSenderProtocolAddress ), ( void * )pxARPHeader->ucSenderProtocolAddress, sizeof( ulSenderProtocolAddress ) );
+ /* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */
+ ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress;
+
+ traceARP_PACKET_RECEIVED();
+
+ /* Don't do anything if the local IP address is zero because
+ that means a DHCP request has not completed. */
+ if( *ipLOCAL_IP_ADDRESS_POINTER != 0UL )
+ {
+ switch( pxARPHeader->usOperation )
+ {
+ case ipARP_REQUEST :
+ /* The packet contained an ARP request. Was it for the IP
+ address of the node running this code? */
+ if( ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
+ {
+ iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress );
+
+ /* The request is for the address of this node. Add the
+ entry into the ARP cache, or refresh the entry if it
+ already exists. */
+ vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
+
+ /* Generate a reply payload in the same buffer. */
+ pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY;
+ if( ulTargetProtocolAddress == ulSenderProtocolAddress )
+ {
+ /* A double IP address is detected! */
+ /* Give the sources MAC address the value of the broadcast address, will be swapped later */
+ memcpy( pxARPFrame->xEthernetHeader.xSourceAddress.ucBytes, xBroadcastMACAddress.ucBytes, sizeof( xBroadcastMACAddress ) );
+ memset( pxARPHeader->xTargetHardwareAddress.ucBytes, '\0', sizeof( MACAddress_t ) );
+ pxARPHeader->ulTargetProtocolAddress = 0UL;
+ }
+ else
+ {
+ memcpy( pxARPHeader->xTargetHardwareAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( MACAddress_t ) );
+ pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress;
+ }
+ memcpy( pxARPHeader->xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );
+ memcpy( ( void* )pxARPHeader->ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPHeader->ucSenderProtocolAddress ) );
+
+ eReturn = eReturnEthernetFrame;
+ }
+ break;
+
+ case ipARP_REPLY :
+ iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress );
+ vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
+ /* Process received ARP frame to see if there is a clash. */
+ #if( ipconfigARP_USE_CLASH_DETECTION != 0 )
+ {
+ if( ulSenderProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
+ {
+ xARPHadIPClash = pdTRUE;
+ memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) );
+ }
+ }
+ #endif /* ipconfigARP_USE_CLASH_DETECTION */
+ break;
+
+ default :
+ /* Invalid. */
+ break;
+ }
+ }
+
+ return eReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )
+
+ uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress )
+ {
+ BaseType_t x;
+ uint32_t lResult = 0;
+
+ /* For each entry in the ARP cache table. */
+ for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+ {
+ if( ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )
+ {
+ lResult = xARPCache[ x ].ulIPAddress;
+ memset( &xARPCache[ x ], '\0', sizeof( xARPCache[ x ] ) );
+ break;
+ }
+ }
+
+ return lResult;
+ }
+
+#endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */
+/*-----------------------------------------------------------*/
+
+void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress, const uint32_t ulIPAddress )
+{
+BaseType_t x, xIpEntry = -1, xMacEntry = -1, xUseEntry = 0;
+uint8_t ucMinAgeFound = 0U;
+
+ #if( ipconfigARP_STORES_REMOTE_ADDRESSES == 0 )
+ /* Only process the IP address if it is on the local network.
+ Unless: when '*ipLOCAL_IP_ADDRESS_POINTER' equals zero, the IP-address
+ and netmask are still unknown. */
+ if( ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) ) ||
+ ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
+ #else
+ /* If ipconfigARP_STORES_REMOTE_ADDRESSES is non-zero, IP addresses with
+ a different netmask will also be stored. After when replying to a UDP
+ message from a different netmask, the IP address can be looped up and a
+ reply sent. This option is useful for systems with multiple gateways,
+ the reply will surely arrive. If ipconfigARP_STORES_REMOTE_ADDRESSES is
+ zero the the gateway address is the only option. */
+ if( pdTRUE )
+ #endif
+ {
+ /* Start with the maximum possible number. */
+ ucMinAgeFound--;
+
+ /* For each entry in the ARP cache table. */
+ for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+ {
+ /* Does this line in the cache table hold an entry for the IP
+ address being queried? */
+ if( xARPCache[ x ].ulIPAddress == ulIPAddress )
+ {
+ if( pxMACAddress == NULL )
+ {
+ /* In case the parameter pxMACAddress is NULL, an entry will be reserved to
+ indicate that there is an outstanding ARP request, This entry will have
+ "ucValid == pdFALSE". */
+ xIpEntry = x;
+ break;
+ }
+
+ /* See if the MAC-address also matches. */
+ if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 )
+ {
+ /* This function will be called for each received packet
+ As this is by far the most common path the coding standard
+ is relaxed in this case and a return is permitted as an
+ optimisation. */
+ xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
+ xARPCache[ x ].ucValid = ( uint8_t ) pdTRUE;
+ return;
+ }
+
+ /* Found an entry containing ulIPAddress, but the MAC address
+ doesn't match. Might be an entry with ucValid=pdFALSE, waiting
+ for an ARP reply. Still want to see if there is match with the
+ given MAC address.ucBytes. If found, either of the two entries
+ must be cleared. */
+ xIpEntry = x;
+ }
+ else if( ( pxMACAddress != NULL ) && ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )
+ {
+ /* Found an entry with the given MAC-address, but the IP-address
+ is different. Continue looping to find a possible match with
+ ulIPAddress. */
+ #if( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 )
+ /* If ARP stores the MAC address of IP addresses outside the
+ network, than the MAC address of the gateway should not be
+ overwritten. */
+ BaseType_t bIsLocal[ 2 ];
+ bIsLocal[ 0 ] = ( ( xARPCache[ x ].ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
+ bIsLocal[ 1 ] = ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
+ if( bIsLocal[ 0 ] == bIsLocal[ 1 ] )
+ {
+ xMacEntry = x;
+ }
+ #else
+ xMacEntry = x;
+ #endif
+ }
+ /* _HT_
+ Shouldn't we test for xARPCache[ x ].ucValid == pdFALSE here ? */
+ else if( xARPCache[ x ].ucAge < ucMinAgeFound )
+ {
+ /* As the table is traversed, remember the table row that
+ contains the oldest entry (the lowest age count, as ages are
+ decremented to zero) so the row can be re-used if this function
+ needs to add an entry that does not already exist. */
+ ucMinAgeFound = xARPCache[ x ].ucAge;
+ xUseEntry = x;
+ }
+ }
+
+ if( xMacEntry >= 0 )
+ {
+ xUseEntry = xMacEntry;
+
+ if( xIpEntry >= 0 )
+ {
+ /* Both the MAC address as well as the IP address were found in
+ different locations: clear the entry which matches the
+ IP-address */
+ memset( &xARPCache[ xIpEntry ], '\0', sizeof( xARPCache[ xIpEntry ] ) );
+ }
+ }
+ else if( xIpEntry >= 0 )
+ {
+ /* An entry containing the IP-address was found, but it had a different MAC address */
+ xUseEntry = xIpEntry;
+ }
+
+ /* If the entry was not found, we use the oldest entry and set the IPaddress */
+ xARPCache[ xUseEntry ].ulIPAddress = ulIPAddress;
+
+ if( pxMACAddress != NULL )
+ {
+ memcpy( xARPCache[ xUseEntry ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) );
+
+ iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, (*pxMACAddress) );
+ /* And this entry does not need immediate attention */
+ xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
+ xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdTRUE;
+ }
+ else if( xIpEntry < 0 )
+ {
+ xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_RETRANSMISSIONS;
+ xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdFALSE;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_ARP_REVERSED_LOOKUP == 1 )
+ eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress, uint32_t *pulIPAddress )
+ {
+ BaseType_t x;
+ eARPLookupResult_t eReturn = eARPCacheMiss;
+
+ /* Loop through each entry in the ARP cache. */
+ for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+ {
+ /* Does this row in the ARP cache table hold an entry for the MAC
+ address being searched? */
+ if( memcmp( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
+ {
+ *pulIPAddress = xARPCache[ x ].ulIPAddress;
+ eReturn = eARPCacheHit;
+ break;
+ }
+ }
+
+ return eReturn;
+ }
+#endif /* ipconfigUSE_ARP_REVERSED_LOOKUP */
+
+/*-----------------------------------------------------------*/
+
+eARPLookupResult_t eARPGetCacheEntry( uint32_t *pulIPAddress, MACAddress_t * const pxMACAddress )
+{
+eARPLookupResult_t eReturn;
+uint32_t ulAddressToLookup;
+
+#if( ipconfigUSE_LLMNR == 1 )
+ if( *pulIPAddress == ipLLMNR_IP_ADDR ) /* Is in network byte order. */
+ {
+ /* The LLMNR IP-address has a fixed virtual MAC address. */
+ memcpy( pxMACAddress->ucBytes, xLLMNR_MacAdress.ucBytes, sizeof( MACAddress_t ) );
+ eReturn = eARPCacheHit;
+ }
+ else
+#endif
+ if( ( *pulIPAddress == ipBROADCAST_IP_ADDRESS ) || /* Is it the general broadcast address 255.255.255.255? */
+ ( *pulIPAddress == xNetworkAddressing.ulBroadcastAddress ) )/* Or a local broadcast address, eg 192.168.1.255? */
+ {
+ /* This is a broadcast so uses the broadcast MAC address. */
+ memcpy( pxMACAddress->ucBytes, xBroadcastMACAddress.ucBytes, sizeof( MACAddress_t ) );
+ eReturn = eARPCacheHit;
+ }
+ else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL )
+ {
+ /* The IP address has not yet been assigned, so there is nothing that
+ can be done. */
+ eReturn = eCantSendPacket;
+ }
+ else
+ {
+ eReturn = eARPCacheMiss;
+
+ if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )
+ {
+#if( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )
+ eReturn = prvCacheLookup( *pulIPAddress, pxMACAddress );
+
+ if( eReturn == eARPCacheHit )
+ {
+ /* The stack is configured to store 'remote IP addresses', i.e. addresses
+ belonging to a different the netmask. prvCacheLookup() returned a hit, so
+ the MAC address is known */
+ }
+ else
+#endif
+ {
+ /* The IP address is off the local network, so look up the
+ hardware address of the router, if any. */
+ if( xNetworkAddressing.ulGatewayAddress != ( uint32_t )0u )
+ {
+ ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;
+ }
+ else
+ {
+ ulAddressToLookup = *pulIPAddress;
+ }
+ }
+ }
+ else
+ {
+ /* The IP address is on the local network, so lookup the requested
+ IP address directly. */
+ ulAddressToLookup = *pulIPAddress;
+ }
+
+ if( eReturn == eARPCacheMiss )
+ {
+ if( ulAddressToLookup == 0UL )
+ {
+ /* The address is not on the local network, and there is not a
+ router. */
+ eReturn = eCantSendPacket;
+ }
+ else
+ {
+ eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress );
+
+ if( eReturn == eARPCacheMiss )
+ {
+ /* It might be that the ARP has to go to the gateway. */
+ *pulIPAddress = ulAddressToLookup;
+ }
+ }
+ }
+ }
+
+ return eReturn;
+}
+
+/*-----------------------------------------------------------*/
+
+static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress )
+{
+BaseType_t x;
+eARPLookupResult_t eReturn = eARPCacheMiss;
+
+ /* Loop through each entry in the ARP cache. */
+ for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+ {
+ /* Does this row in the ARP cache table hold an entry for the IP address
+ being queried? */
+ if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )
+ {
+ /* A matching valid entry was found. */
+ if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
+ {
+ /* This entry is waiting an ARP reply, so is not valid. */
+ eReturn = eCantSendPacket;
+ }
+ else
+ {
+ /* A valid entry was found. */
+ memcpy( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) );
+ eReturn = eARPCacheHit;
+ }
+ break;
+ }
+ }
+
+ return eReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vARPAgeCache( void )
+{
+BaseType_t x;
+TickType_t xTimeNow;
+
+ /* Loop through each entry in the ARP cache. */
+ for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+ {
+ /* If the entry is valid (its age is greater than zero). */
+ if( xARPCache[ x ].ucAge > 0U )
+ {
+ /* Decrement the age value of the entry in this ARP cache table row.
+ When the age reaches zero it is no longer considered valid. */
+ ( xARPCache[ x ].ucAge )--;
+
+ /* If the entry is not yet valid, then it is waiting an ARP
+ reply, and the ARP request should be retransmitted. */
+ if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
+ {
+ FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
+ }
+ else if( xARPCache[ x ].ucAge <= ( uint8_t ) arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )
+ {
+ /* This entry will get removed soon. See if the MAC address is
+ still valid to prevent this happening. */
+ iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );
+ FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
+ }
+ else
+ {
+ /* The age has just ticked down, with nothing to do. */
+ }
+
+ if( xARPCache[ x ].ucAge == 0u )
+ {
+ /* The entry is no longer valid. Wipe it out. */
+ iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );
+ xARPCache[ x ].ulIPAddress = 0UL;
+ }
+ }
+ }
+
+ xTimeNow = xTaskGetTickCount ();
+
+ if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) )
+ {
+ FreeRTOS_OutputARPRequest( *ipLOCAL_IP_ADDRESS_POINTER );
+ xLastGratuitousARPTime = xTimeNow;
+ }
+}
+/*-----------------------------------------------------------*/
+
+void vARPSendGratuitous( void )
+{
+ /* Setting xLastGratuitousARPTime to 0 will force a gratuitous ARP the next
+ time vARPAgeCache() is called. */
+ xLastGratuitousARPTime = ( TickType_t ) 0;
+
+ /* Let the IP-task call vARPAgeCache(). */
+ xSendEventToIPTask( eARPTimerEvent );
+}
+
+/*-----------------------------------------------------------*/
+void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress )
+{
+NetworkBufferDescriptor_t *pxNetworkBuffer;
+
+ /* This is called from the context of the IP event task, so a block time
+ must not be used. */
+ pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( ARPPacket_t ), ( TickType_t ) 0 );
+
+ if( pxNetworkBuffer != NULL )
+ {
+ pxNetworkBuffer->ulIPAddress = ulIPAddress;
+ vARPGenerateRequestPacket( pxNetworkBuffer );
+
+ #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+ {
+ if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+ {
+ BaseType_t xIndex;
+
+ 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
+
+ xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
+ }
+}
+
+void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
+{
+ARPPacket_t *pxARPPacket;
+
+ pxARPPacket = ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
+
+ /* memcpy the const part of the header information into the correct
+ location in the packet. This copies:
+ xEthernetHeader.ulDestinationAddress
+ xEthernetHeader.usFrameType;
+ xARPHeader.usHardwareType;
+ xARPHeader.usProtocolType;
+ xARPHeader.ucHardwareAddressLength;
+ xARPHeader.ucProtocolAddressLength;
+ xARPHeader.usOperation;
+ xARPHeader.xTargetHardwareAddress;
+ */
+ memcpy( ( void * ) &( pxARPPacket->xEthernetHeader ), ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) );
+ memcpy( ( void * ) pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
+ memcpy( ( void * ) pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
+
+ memcpy( ( void* )pxARPPacket->xARPHeader.ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );
+ pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;
+
+ pxNetworkBuffer->xDataLength = sizeof( ARPPacket_t );
+
+ iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->ulIPAddress );
+}
+/*-----------------------------------------------------------*/
+
+void FreeRTOS_ClearARP( void )
+{
+ memset( xARPCache, '\0', sizeof( xARPCache ) );
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 )
+
+ void FreeRTOS_PrintARPCache( void )
+ {
+ BaseType_t x, xCount = 0;
+
+ /* Loop through each entry in the ARP cache. */
+ for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+ {
+ if( ( xARPCache[ x ].ulIPAddress != 0ul ) && ( xARPCache[ x ].ucAge > 0U ) )
+ {
+ /* See if the MAC-address also matches, and we're all happy */
+ FreeRTOS_printf( ( "Arp %2ld: %3u - %16lxip : %02x:%02x:%02x : %02x:%02x:%02x\n",
+ x,
+ xARPCache[ x ].ucAge,
+ xARPCache[ x ].ulIPAddress,
+ xARPCache[ x ].xMACAddress.ucBytes[0],
+ xARPCache[ x ].xMACAddress.ucBytes[1],
+ xARPCache[ x ].xMACAddress.ucBytes[2],
+ xARPCache[ x ].xMACAddress.ucBytes[3],
+ xARPCache[ x ].xMACAddress.ucBytes[4],
+ xARPCache[ x ].xMACAddress.ucBytes[5] ) );
+ xCount++;
+ }
+ }
+
+ FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) );
+ }
+
+#endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c
new file mode 100644
index 000000000..2e3377a71
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c
@@ -0,0 +1,1015 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_TCP_IP.h"
+#include "FreeRTOS_DHCP.h"
+#include "FreeRTOS_ARP.h"
+#include "NetworkInterface.h"
+#include "NetworkBufferManagement.h"
+
+/* Exclude the entire file if DHCP is not enabled. */
+#if( ipconfigUSE_DHCP != 0 )
+
+#if ( ipconfigUSE_DHCP != 0 ) && ( ipconfigNETWORK_MTU < 586u )
+ /* DHCP must be able to receive an options field of 312 bytes, the fixed
+ part of the DHCP packet is 240 bytes, and the IP/UDP headers take 28 bytes. */
+ #error ipconfigNETWORK_MTU needs to be at least 586 to use DHCP
+#endif
+
+/* Parameter widths in the DHCP packet. */
+#define dhcpCLIENT_HARDWARE_ADDRESS_LENGTH 16
+#define dhcpSERVER_HOST_NAME_LENGTH 64
+#define dhcpBOOT_FILE_NAME_LENGTH 128
+
+/* Timer parameters */
+#ifndef dhcpINITIAL_DHCP_TX_PERIOD
+ #define dhcpINITIAL_TIMER_PERIOD ( pdMS_TO_TICKS( 250 ) )
+ #define dhcpINITIAL_DHCP_TX_PERIOD ( pdMS_TO_TICKS( 5000 ) )
+#endif
+
+/* Codes of interest found in the DHCP options field. */
+#define dhcpIPv4_ZERO_PAD_OPTION_CODE ( 0u )
+#define dhcpIPv4_SUBNET_MASK_OPTION_CODE ( 1u )
+#define dhcpIPv4_GATEWAY_OPTION_CODE ( 3u )
+#define dhcpIPv4_DNS_SERVER_OPTIONS_CODE ( 6u )
+#define dhcpIPv4_DNS_HOSTNAME_OPTIONS_CODE ( 12u )
+#define dhcpIPv4_REQUEST_IP_ADDRESS_OPTION_CODE ( 50u )
+#define dhcpIPv4_LEASE_TIME_OPTION_CODE ( 51u )
+#define dhcpIPv4_MESSAGE_TYPE_OPTION_CODE ( 53u )
+#define dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE ( 54u )
+#define dhcpIPv4_PARAMETER_REQUEST_OPTION_CODE ( 55u )
+#define dhcpIPv4_CLIENT_IDENTIFIER_OPTION_CODE ( 61u )
+
+/* The four DHCP message types of interest. */
+#define dhcpMESSAGE_TYPE_DISCOVER ( 1 )
+#define dhcpMESSAGE_TYPE_OFFER ( 2 )
+#define dhcpMESSAGE_TYPE_REQUEST ( 3 )
+#define dhcpMESSAGE_TYPE_ACK ( 5 )
+#define dhcpMESSAGE_TYPE_NACK ( 6 )
+
+/* Offsets into the transmitted DHCP options fields at which various parameters
+are located. */
+#define dhcpCLIENT_IDENTIFIER_OFFSET ( 5 )
+#define dhcpREQUESTED_IP_ADDRESS_OFFSET ( 13 )
+#define dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ( 19 )
+
+/* Values used in the DHCP packets. */
+#define dhcpREQUEST_OPCODE ( 1 )
+#define dhcpREPLY_OPCODE ( 2 )
+#define dhcpADDRESS_TYPE_ETHERNET ( 1 )
+#define dhcpETHERNET_ADDRESS_LENGTH ( 6 )
+
+/* If a lease time is not received, use the default of two days. */
+/* 48 hours in ticks. Can not use pdMS_TO_TICKS() as integer overflow can occur. */
+#define dhcpDEFAULT_LEASE_TIME ( ( 48UL * 60UL * 60UL ) * configTICK_RATE_HZ )
+
+/* Don't allow the lease time to be too short. */
+#define dhcpMINIMUM_LEASE_TIME ( pdMS_TO_TICKS( 60000UL ) ) /* 60 seconds in ticks. */
+
+/* Marks the end of the variable length options field in the DHCP packet. */
+#define dhcpOPTION_END_BYTE 0xffu
+
+/* Offset into a DHCP message at which the first byte of the options is
+located. */
+#define dhcpFIRST_OPTION_BYTE_OFFSET ( 0xf0 )
+
+/* When walking the variable length options field, the following value is used
+to ensure the walk has not gone past the end of the valid options. 2 bytes is
+made up of the length byte, and minimum one byte value. */
+#define dhcpMAX_OPTION_LENGTH_OF_INTEREST ( 2L )
+
+/* Standard DHCP port numbers and magic cookie value.
+DHCPv4 uses UDP port number 68 for clients and port number 67 for servers.
+*/
+#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
+ #define dhcpCLIENT_PORT 0x4400u
+ #define dhcpSERVER_PORT 0x4300u
+ #define dhcpCOOKIE 0x63538263ul
+ #define dhcpBROADCAST 0x0080u
+#else
+ #define dhcpCLIENT_PORT 0x0044u
+ #define dhcpSERVER_PORT 0x0043u
+ #define dhcpCOOKIE 0x63825363ul
+ #define dhcpBROADCAST 0x8000u
+#endif /* ipconfigBYTE_ORDER */
+
+#include "pack_struct_start.h"
+struct xDHCPMessage
+{
+ uint8_t ucOpcode;
+ uint8_t ucAddressType;
+ uint8_t ucAddressLength;
+ uint8_t ucHops;
+ uint32_t ulTransactionID;
+ uint16_t usElapsedTime;
+ uint16_t usFlags;
+ uint32_t ulClientIPAddress_ciaddr;
+ uint32_t ulYourIPAddress_yiaddr;
+ uint32_t ulServerIPAddress_siaddr;
+ uint32_t ulRelayAgentIPAddress_giaddr;
+ uint8_t ucClientHardwareAddress[ dhcpCLIENT_HARDWARE_ADDRESS_LENGTH ];
+ uint8_t ucServerHostName[ dhcpSERVER_HOST_NAME_LENGTH ];
+ uint8_t ucBootFileName[ dhcpBOOT_FILE_NAME_LENGTH ];
+ uint32_t ulDHCPCookie;
+ uint8_t ucFirstOptionByte;
+}
+#include "pack_struct_end.h"
+typedef struct xDHCPMessage DHCPMessage_t;
+
+/* DHCP state machine states. */
+typedef enum
+{
+ eWaitingSendFirstDiscover = 0, /* Initial state. Send a discover the first time it is called, and reset all timers. */
+ eWaitingOffer, /* Either resend the discover, or, if the offer is forthcoming, send a request. */
+ eWaitingAcknowledge, /* Either resend the request. */
+ #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+ eGetLinkLayerAddress, /* When DHCP didn't respond, try to obtain a LinkLayer address 168.254.x.x. */
+ #endif
+ eLeasedAddress, /* Resend the request at the appropriate time to renew the lease. */
+ eNotUsingLeasedAddress /* DHCP failed, and a default IP address is being used. */
+} eDHCPState_t;
+
+/* Hold information in between steps in the DHCP state machine. */
+struct xDHCP_DATA
+{
+ uint32_t ulTransactionId;
+ uint32_t ulOfferedIPAddress;
+ uint32_t ulDHCPServerAddress;
+ uint32_t ulLeaseTime;
+ /* Hold information on the current timer state. */
+ TickType_t xDHCPTxTime;
+ TickType_t xDHCPTxPeriod;
+ /* Try both without and with the broadcast flag */
+ BaseType_t xUseBroadcast;
+ /* Maintains the DHCP state machine state. */
+ eDHCPState_t eDHCPState;
+ /* The UDP socket used for all incoming and outgoing DHCP traffic. */
+ Socket_t xDHCPSocket;
+};
+
+typedef struct xDHCP_DATA DHCPData_t;
+
+#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+ /* Define the Link Layer IP address: 169.254.x.x */
+ #define LINK_LAYER_ADDRESS_0 169
+ #define LINK_LAYER_ADDRESS_1 254
+
+ /* Define the netmask used: 255.255.0.0 */
+ #define LINK_LAYER_NETMASK_0 255
+ #define LINK_LAYER_NETMASK_1 255
+ #define LINK_LAYER_NETMASK_2 0
+ #define LINK_LAYER_NETMASK_3 0
+#endif
+
+
+/*
+ * Generate a DHCP discover message and send it on the DHCP socket.
+ */
+static void prvSendDHCPDiscover( void );
+
+/*
+ * Interpret message received on the DHCP socket.
+ */
+static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType );
+
+/*
+ * Generate a DHCP request packet, and send it on the DHCP socket.
+ */
+static void prvSendDHCPRequest( void );
+
+/*
+ * Prepare to start a DHCP transaction. This initialises some state variables
+ * and creates the DHCP socket if necessary.
+ */
+static void prvInitialiseDHCP( void );
+
+/*
+ * Creates the part of outgoing DHCP messages that are common to all outgoing
+ * DHCP messages.
+ */
+static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, BaseType_t xOpcode, const uint8_t * const pucOptionsArray, size_t *pxOptionsArraySize );
+
+/*
+ * Create the DHCP socket, if it has not been created already.
+ */
+static void prvCreateDHCPSocket( void );
+
+/*
+ * After DHCP has failed to answer, prepare everything to start searching
+ * for (trying-out) LinkLayer IP-addresses, using the random method: Send
+ * a gratuitous ARP request and wait if another device responds to it.
+ */
+#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+ static void prvPrepareLinkLayerIPLookUp( void );
+#endif
+
+/*-----------------------------------------------------------*/
+
+/* The next DHCP transaction Id to be used. */
+static DHCPData_t xDHCPData;
+
+/*-----------------------------------------------------------*/
+
+BaseType_t xIsDHCPSocket( Socket_t xSocket )
+{
+BaseType_t xReturn;
+
+ if( xDHCPData.xDHCPSocket == xSocket )
+ {
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vDHCPProcess( BaseType_t xReset )
+{
+BaseType_t xGivingUp = pdFALSE;
+#if( ipconfigUSE_DHCP_HOOK != 0 )
+ eDHCPCallbackAnswer_t eAnswer;
+#endif /* ipconfigUSE_DHCP_HOOK */
+
+ /* Is DHCP starting over? */
+ if( xReset != pdFALSE )
+ {
+ xDHCPData.eDHCPState = eWaitingSendFirstDiscover;
+ }
+
+ switch( xDHCPData.eDHCPState )
+ {
+ case eWaitingSendFirstDiscover :
+ /* Ask the user if a DHCP discovery is required. */
+ #if( ipconfigUSE_DHCP_HOOK != 0 )
+ eAnswer = xApplicationDHCPHook( eDHCPPhasePreDiscover, xNetworkAddressing.ulDefaultIPAddress );
+ if( eAnswer == eDHCPContinue )
+ #endif /* ipconfigUSE_DHCP_HOOK */
+ {
+ /* Initial state. Create the DHCP socket, timer, etc. if they
+ have not already been created. */
+ prvInitialiseDHCP();
+
+ /* See if prvInitialiseDHCP() has creates a socket. */
+ if( xDHCPData.xDHCPSocket == NULL )
+ {
+ xGivingUp = pdTRUE;
+ break;
+ }
+
+ *ipLOCAL_IP_ADDRESS_POINTER = 0UL;
+
+ /* Send the first discover request. */
+ if( xDHCPData.xDHCPSocket != NULL )
+ {
+ xDHCPData.xDHCPTxTime = xTaskGetTickCount();
+ prvSendDHCPDiscover( );
+ xDHCPData.eDHCPState = eWaitingOffer;
+ }
+ }
+ #if( ipconfigUSE_DHCP_HOOK != 0 )
+ else
+ {
+ if( eAnswer == eDHCPUseDefaults )
+ {
+ memcpy( &xNetworkAddressing, &xDefaultAddressing, sizeof( xNetworkAddressing ) );
+ }
+
+ /* The user indicates that the DHCP process does not continue. */
+ xGivingUp = pdTRUE;
+ }
+ #endif /* ipconfigUSE_DHCP_HOOK */
+ break;
+
+ case eWaitingOffer :
+
+ xGivingUp = pdFALSE;
+
+ /* Look for offers coming in. */
+ if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_OFFER ) == pdPASS )
+ {
+ #if( ipconfigUSE_DHCP_HOOK != 0 )
+ /* Ask the user if a DHCP request is required. */
+ eAnswer = xApplicationDHCPHook( eDHCPPhasePreRequest, xDHCPData.ulOfferedIPAddress );
+
+ if( eAnswer == eDHCPContinue )
+ #endif /* ipconfigUSE_DHCP_HOOK */
+ {
+ /* An offer has been made, the user wants to continue,
+ generate the request. */
+ xDHCPData.xDHCPTxTime = xTaskGetTickCount();
+ xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
+ prvSendDHCPRequest( );
+ xDHCPData.eDHCPState = eWaitingAcknowledge;
+ break;
+ }
+
+ #if( ipconfigUSE_DHCP_HOOK != 0 )
+ if( eAnswer == eDHCPUseDefaults )
+ {
+ memcpy( &xNetworkAddressing, &xDefaultAddressing, sizeof( xNetworkAddressing ) );
+ }
+
+ /* The user indicates that the DHCP process does not continue. */
+ xGivingUp = pdTRUE;
+ #endif /* ipconfigUSE_DHCP_HOOK */
+ }
+ else if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )
+ {
+ /* It is time to send another Discover. Increase the time
+ period, and if it has not got to the point of giving up - send
+ another discovery. */
+ xDHCPData.xDHCPTxPeriod <<= 1;
+
+ if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
+ {
+ xDHCPData.ulTransactionId++;
+ xDHCPData.xDHCPTxTime = xTaskGetTickCount();
+ xDHCPData.xUseBroadcast = !xDHCPData.xUseBroadcast;
+ prvSendDHCPDiscover( );
+ FreeRTOS_debug_printf( ( "vDHCPProcess: timeout %lu ticks\n", xDHCPData.xDHCPTxPeriod ) );
+ }
+ else
+ {
+ FreeRTOS_debug_printf( ( "vDHCPProcess: giving up %lu > %lu ticks\n", xDHCPData.xDHCPTxPeriod, ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) );
+
+ #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+ {
+ /* Only use a fake Ack if the default IP address == 0x00
+ and the link local addressing is used. Start searching
+ a free LinkLayer IP-address. Next state will be
+ 'eGetLinkLayerAddress'. */
+ prvPrepareLinkLayerIPLookUp();
+
+ /* Setting an IP address manually so set to not using
+ leased address mode. */
+ xDHCPData.eDHCPState = eGetLinkLayerAddress;
+ }
+ #else
+ {
+ xGivingUp = pdTRUE;
+ }
+ #endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
+ }
+ }
+ break;
+
+ case eWaitingAcknowledge :
+
+ /* Look for acks coming in. */
+ if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_ACK ) == pdPASS )
+ {
+ FreeRTOS_debug_printf( ( "vDHCPProcess: acked %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );
+
+ /* DHCP completed. The IP address can now be used, and the
+ timer set to the lease timeout time. */
+ *ipLOCAL_IP_ADDRESS_POINTER = xDHCPData.ulOfferedIPAddress;
+
+ /* Setting the 'local' broadcast address, something like
+ '192.168.1.255'. */
+ xNetworkAddressing.ulBroadcastAddress = ( xDHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask;
+ xDHCPData.eDHCPState = eLeasedAddress;
+
+ iptraceDHCP_SUCCEDEED( xDHCPData.ulOfferedIPAddress );
+
+ /* DHCP failed, the default configured IP-address will be used
+ Now call vIPNetworkUpCalls() to send the network-up event and
+ start the ARP timer. */
+ vIPNetworkUpCalls( );
+
+ /* Close socket to ensure packets don't queue on it. */
+ vSocketClose( xDHCPData.xDHCPSocket );
+ xDHCPData.xDHCPSocket = NULL;
+
+ if( xDHCPData.ulLeaseTime == 0UL )
+ {
+ xDHCPData.ulLeaseTime = dhcpDEFAULT_LEASE_TIME;
+ }
+ else if( xDHCPData.ulLeaseTime < dhcpMINIMUM_LEASE_TIME )
+ {
+ xDHCPData.ulLeaseTime = dhcpMINIMUM_LEASE_TIME;
+ }
+ else
+ {
+ /* The lease time is already valid. */
+ }
+
+ /* Check for clashes. */
+ vARPSendGratuitous();
+ vIPReloadDHCPTimer( xDHCPData.ulLeaseTime );
+ }
+ else
+ {
+ /* Is it time to send another Discover? */
+ if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )
+ {
+ /* Increase the time period, and if it has not got to the
+ point of giving up - send another request. */
+ xDHCPData.xDHCPTxPeriod <<= 1;
+
+ if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
+ {
+ xDHCPData.xDHCPTxTime = xTaskGetTickCount();
+ prvSendDHCPRequest( );
+ }
+ else
+ {
+ /* Give up, start again. */
+ xDHCPData.eDHCPState = eWaitingSendFirstDiscover;
+ }
+ }
+ }
+ break;
+
+ #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+ case eGetLinkLayerAddress:
+ if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )
+ {
+ if( xARPHadIPClash == pdFALSE )
+ {
+ /* ARP OK. proceed. */
+ iptraceDHCP_SUCCEDEED( xDHCPData.ulOfferedIPAddress );
+
+ /* Auto-IP succeeded, the default configured IP-address will
+ be used. Now call vIPNetworkUpCalls() to send the
+ network-up event and start the ARP timer. */
+ vIPNetworkUpCalls( );
+ xDHCPData.eDHCPState = eNotUsingLeasedAddress;
+ }
+ else
+ {
+ /* ARP clashed - try another IP address. */
+ prvPrepareLinkLayerIPLookUp();
+
+ /* Setting an IP address manually so set to not using leased
+ address mode. */
+ xDHCPData.eDHCPState = eGetLinkLayerAddress;
+ }
+ }
+ break;
+ #endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
+
+ case eLeasedAddress :
+
+ /* Resend the request at the appropriate time to renew the lease. */
+ prvCreateDHCPSocket();
+
+ if( xDHCPData.xDHCPSocket != NULL )
+ {
+ xDHCPData.xDHCPTxTime = xTaskGetTickCount();
+ xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
+ prvSendDHCPRequest( );
+ xDHCPData.eDHCPState = eWaitingAcknowledge;
+
+ /* From now on, we should be called more often */
+ vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD );
+ }
+ break;
+
+ case eNotUsingLeasedAddress:
+
+ vIPSetDHCPTimerEnableState( pdFALSE );
+ break;
+
+ default:
+ break;
+ }
+
+ if( xGivingUp != pdFALSE )
+ {
+ /* xGivingUp became true either because of a time-out, or because
+ xApplicationDHCPHook() returned another value than 'eDHCPContinue',
+ meaning that the conversion is cancelled from here. */
+
+ /* Revert to static IP address. */
+ taskENTER_CRITICAL();
+ {
+ *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;
+ iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( xNetworkAddressing.ulDefaultIPAddress );
+ }
+ taskEXIT_CRITICAL();
+
+ xDHCPData.eDHCPState = eNotUsingLeasedAddress;
+ vIPSetDHCPTimerEnableState( pdFALSE );
+
+ /* DHCP failed, the default configured IP-address will be used. Now
+ call vIPNetworkUpCalls() to send the network-up event and start the ARP
+ timer. */
+ vIPNetworkUpCalls( );
+
+ /* Test if socket was indeed created. */
+ if( xDHCPData.xDHCPSocket != NULL )
+ {
+ /* Close socket to ensure packets don't queue on it. */
+ vSocketClose( xDHCPData.xDHCPSocket );
+ xDHCPData.xDHCPSocket = NULL;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvCreateDHCPSocket( void )
+{
+struct freertos_sockaddr xAddress;
+BaseType_t xReturn;
+TickType_t xTimeoutTime = ( TickType_t ) 0;
+
+ /* Create the socket, if it has not already been created. */
+ if( xDHCPData.xDHCPSocket == NULL )
+ {
+ xDHCPData.xDHCPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
+ if( xDHCPData.xDHCPSocket != FREERTOS_INVALID_SOCKET )
+ {
+
+ /* Ensure the Rx and Tx timeouts are zero as the DHCP executes in the
+ context of the IP task. */
+ FreeRTOS_setsockopt( xDHCPData.xDHCPSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
+ FreeRTOS_setsockopt( xDHCPData.xDHCPSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
+
+ /* Bind to the standard DHCP client port. */
+ xAddress.sin_port = ( uint16_t ) dhcpCLIENT_PORT;
+ xReturn = vSocketBind( xDHCPData.xDHCPSocket, &xAddress, sizeof( xAddress ), pdFALSE );
+ if( xReturn != 0 )
+ {
+ /* Binding failed, close the socket again. */
+ vSocketClose( xDHCPData.xDHCPSocket );
+ xDHCPData.xDHCPSocket = NULL;
+ }
+ }
+ else
+ {
+ /* Change to NULL for easier testing. */
+ xDHCPData.xDHCPSocket = NULL;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvInitialiseDHCP( void )
+{
+ /* Initialise the parameters that will be set by the DHCP process. */
+ if( xDHCPData.ulTransactionId == 0ul )
+ {
+ xDHCPData.ulTransactionId = ipconfigRAND32();
+ }
+ else
+ {
+ xDHCPData.ulTransactionId++;
+ }
+
+ xDHCPData.xUseBroadcast = 0;
+ xDHCPData.ulOfferedIPAddress = 0UL;
+ xDHCPData.ulDHCPServerAddress = 0UL;
+ xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
+
+ /* Create the DHCP socket if it has not already been created. */
+ prvCreateDHCPSocket();
+ FreeRTOS_debug_printf( ( "prvInitialiseDHCP: start after %lu ticks\n", dhcpINITIAL_TIMER_PERIOD ) );
+ vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD );
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType )
+{
+uint8_t *pucUDPPayload, *pucLastByte;
+struct freertos_sockaddr xClient;
+uint32_t xClientLength = sizeof( xClient );
+int32_t lBytes;
+DHCPMessage_t *pxDHCPMessage;
+uint8_t *pucByte, ucOptionCode, ucLength;
+uint32_t ulProcessed, ulParameter;
+BaseType_t xReturn = pdFALSE;
+const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct DHCP message type must be present in the options. */
+
+ lBytes = FreeRTOS_recvfrom( xDHCPData.xDHCPSocket, ( void * ) &pucUDPPayload, 0ul, FREERTOS_ZERO_COPY, &xClient, &xClientLength );
+
+ if( lBytes > 0 )
+ {
+ /* Map a DHCP structure onto the received data. */
+ pxDHCPMessage = ( DHCPMessage_t * ) ( pucUDPPayload );
+
+ /* Sanity check. */
+ if( ( pxDHCPMessage->ulDHCPCookie == ( uint32_t ) dhcpCOOKIE ) &&
+ ( pxDHCPMessage->ucOpcode == ( uint8_t ) dhcpREPLY_OPCODE ) &&
+ ( pxDHCPMessage->ulTransactionID == FreeRTOS_htonl( xDHCPData.ulTransactionId ) ) )
+ {
+ if( memcmp( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) ) == 0 )
+ {
+ /* None of the essential options have been processed yet. */
+ ulProcessed = 0ul;
+
+ /* Walk through the options until the dhcpOPTION_END_BYTE byte
+ is found, taking care not to walk off the end of the options. */
+ pucByte = &( pxDHCPMessage->ucFirstOptionByte );
+ pucLastByte = &( pucUDPPayload[ lBytes - dhcpMAX_OPTION_LENGTH_OF_INTEREST ] );
+
+ while( pucByte < pucLastByte )
+ {
+ ucOptionCode = pucByte[ 0 ];
+ if( ucOptionCode == ( uint8_t ) dhcpOPTION_END_BYTE )
+ {
+ /* Ready, the last byte has been seen. */
+ break;
+ }
+ if( ucOptionCode == ( uint8_t ) dhcpIPv4_ZERO_PAD_OPTION_CODE )
+ {
+ /* The value zero is used as a pad byte,
+ it is not followed by a length byte. */
+ pucByte += 1;
+ continue;
+ }
+ ucLength = pucByte[ 1 ];
+ pucByte += 2;
+
+ /* In most cases, a 4-byte network-endian parameter follows,
+ just get it once here and use later */
+ memcpy( ( void * ) &( ulParameter ), ( void * ) pucByte, ( size_t ) sizeof( ulParameter ) );
+
+ switch( ucOptionCode )
+ {
+ case dhcpIPv4_MESSAGE_TYPE_OPTION_CODE :
+
+ if( *pucByte == ( uint8_t ) xExpectedMessageType )
+ {
+ /* The message type is the message type the
+ state machine is expecting. */
+ ulProcessed++;
+ }
+ else
+ {
+ if( *pucByte == ( uint8_t ) dhcpMESSAGE_TYPE_NACK )
+ {
+ if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_ACK )
+ {
+ /* Start again. */
+ xDHCPData.eDHCPState = eWaitingSendFirstDiscover;
+ }
+ }
+ /* Stop processing further options. */
+ ucLength = 0;
+ }
+ break;
+
+ case dhcpIPv4_SUBNET_MASK_OPTION_CODE :
+
+ if( ucLength == sizeof( uint32_t ) )
+ {
+ xNetworkAddressing.ulNetMask = ulParameter;
+ }
+ break;
+
+ case dhcpIPv4_GATEWAY_OPTION_CODE :
+ /* The DHCP server may send more than 1 gateway addresses. */
+ if( ucLength >= sizeof( uint32_t ) )
+ {
+ /* ulProcessed is not incremented in this case
+ because the gateway is not essential. */
+ xNetworkAddressing.ulGatewayAddress = ulParameter;
+ }
+ break;
+
+ case dhcpIPv4_DNS_SERVER_OPTIONS_CODE :
+
+ /* ulProcessed is not incremented in this case
+ because the DNS server is not essential. Only the
+ first DNS server address is taken. */
+ xNetworkAddressing.ulDNSServerAddress = ulParameter;
+ break;
+
+ case dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE :
+
+ if( ucLength == sizeof( uint32_t ) )
+ {
+ if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_OFFER )
+ {
+ /* Offers state the replying server. */
+ ulProcessed++;
+ xDHCPData.ulDHCPServerAddress = ulParameter;
+ }
+ else
+ {
+ /* The ack must come from the expected server. */
+ if( xDHCPData.ulDHCPServerAddress == ulParameter )
+ {
+ ulProcessed++;
+ }
+ }
+ }
+ break;
+
+ case dhcpIPv4_LEASE_TIME_OPTION_CODE :
+
+ if( ucLength == sizeof( xDHCPData.ulLeaseTime ) )
+ {
+ /* ulProcessed is not incremented in this case
+ because the lease time is not essential. */
+ /* The DHCP parameter is in seconds, convert
+ to host-endian format. */
+ xDHCPData.ulLeaseTime = FreeRTOS_ntohl( ulParameter );
+
+ /* Divide the lease time by two to ensure a
+ renew request is sent before the lease actually
+ expires. */
+ xDHCPData.ulLeaseTime >>= 1UL;
+
+ /* Multiply with configTICK_RATE_HZ to get clock
+ ticks. */
+ xDHCPData.ulLeaseTime = configTICK_RATE_HZ * xDHCPData.ulLeaseTime;
+ }
+ break;
+
+ default :
+
+ /* Not interested in this field. */
+
+ break;
+ }
+
+ /* Jump over the data to find the next option code. */
+ if( ucLength == 0u )
+ {
+ break;
+ }
+ else
+ {
+ pucByte += ucLength;
+ }
+ }
+
+ /* Were all the mandatory options received? */
+ if( ulProcessed >= ulMandatoryOptions )
+ {
+ /* HT:endian: used to be network order */
+ xDHCPData.ulOfferedIPAddress = pxDHCPMessage->ulYourIPAddress_yiaddr;
+ FreeRTOS_printf( ( "vDHCPProcess: offer %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );
+ xReturn = pdPASS;
+ }
+ }
+ }
+
+ FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayload );
+ } /* if( lBytes > 0 ) */
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, BaseType_t xOpcode, const uint8_t * const pucOptionsArray, size_t *pxOptionsArraySize )
+{
+DHCPMessage_t *pxDHCPMessage;
+size_t xRequiredBufferSize = sizeof( DHCPMessage_t ) + *pxOptionsArraySize;
+uint8_t *pucUDPPayloadBuffer;
+
+#if( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
+ const char *pucHostName = pcApplicationHostnameHook ();
+ size_t xNameLength = strlen( pucHostName );
+ uint8_t *pucPtr;
+
+ xRequiredBufferSize += ( 2 + xNameLength );
+#endif
+
+ /* Get a buffer. This uses a maximum delay, but the delay will be capped
+ to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value still needs to
+ be test. */
+ do
+ {
+ } while( ( pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xRequiredBufferSize, portMAX_DELAY ) ) == NULL );
+
+ pxDHCPMessage = ( DHCPMessage_t * ) pucUDPPayloadBuffer;
+
+ /* Most fields need to be zero. */
+ memset( ( void * ) pxDHCPMessage, 0x00, sizeof( DHCPMessage_t ) );
+
+ /* Create the message. */
+ pxDHCPMessage->ucOpcode = ( uint8_t ) xOpcode;
+ pxDHCPMessage->ucAddressType = ( uint8_t ) dhcpADDRESS_TYPE_ETHERNET;
+ pxDHCPMessage->ucAddressLength = ( uint8_t ) dhcpETHERNET_ADDRESS_LENGTH;
+
+ /* ulTransactionID doesn't really need a htonl() translation, but when DHCP
+ times out, it is nicer to see an increasing number in this ID field */
+ pxDHCPMessage->ulTransactionID = FreeRTOS_htonl( xDHCPData.ulTransactionId );
+ pxDHCPMessage->ulDHCPCookie = ( uint32_t ) dhcpCOOKIE;
+ if( xDHCPData.xUseBroadcast != pdFALSE )
+ {
+ pxDHCPMessage->usFlags = ( uint16_t ) dhcpBROADCAST;
+ }
+ else
+ {
+ pxDHCPMessage->usFlags = 0u;
+ }
+
+ memcpy( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress[ 0 ] ), ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );
+
+ /* Copy in the const part of the options options. */
+ memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET ] ), ( void * ) pucOptionsArray, *pxOptionsArraySize );
+
+ #if( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
+ {
+ /* With this option, the hostname can be registered as well which makes
+ it easier to lookup a device in a router's list of DHCP clients. */
+
+ /* Point to where the OPTION_END was stored to add data. */
+ pucPtr = &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + ( *pxOptionsArraySize - 1 ) ] );
+ pucPtr[ 0 ] = dhcpIPv4_DNS_HOSTNAME_OPTIONS_CODE;
+ pucPtr[ 1 ] = ( uint8_t ) xNameLength;
+ memcpy( ( void *) ( pucPtr + 2 ), pucHostName, xNameLength );
+ pucPtr[ 2 + xNameLength ] = dhcpOPTION_END_BYTE;
+ *pxOptionsArraySize += ( 2 + xNameLength );
+ }
+ #endif
+
+ /* Map in the client identifier. */
+ memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpCLIENT_IDENTIFIER_OFFSET ] ),
+ ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );
+
+ /* Set the addressing. */
+ pxAddress->sin_addr = ipBROADCAST_IP_ADDRESS;
+ pxAddress->sin_port = ( uint16_t ) dhcpSERVER_PORT;
+
+ return pucUDPPayloadBuffer;
+}
+/*-----------------------------------------------------------*/
+
+static void prvSendDHCPRequest( void )
+{
+uint8_t *pucUDPPayloadBuffer;
+struct freertos_sockaddr xAddress;
+static const uint8_t ucDHCPRequestOptions[] =
+{
+ /* Do not change the ordering without also changing
+ dhcpCLIENT_IDENTIFIER_OFFSET, dhcpREQUESTED_IP_ADDRESS_OFFSET and
+ dhcpDHCP_SERVER_IP_ADDRESS_OFFSET. */
+ dhcpIPv4_MESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_REQUEST, /* Message type option. */
+ dhcpIPv4_CLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */
+ dhcpIPv4_REQUEST_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address being requested. */
+ dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address of the DHCP server. */
+ dhcpOPTION_END_BYTE
+};
+size_t xOptionsLength = sizeof( ucDHCPRequestOptions );
+
+ pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, ( uint8_t ) dhcpREQUEST_OPCODE, ucDHCPRequestOptions, &xOptionsLength );
+
+ /* Copy in the IP address being requested. */
+ memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpREQUESTED_IP_ADDRESS_OFFSET ] ),
+ ( void * ) &( xDHCPData.ulOfferedIPAddress ), sizeof( xDHCPData.ulOfferedIPAddress ) );
+
+ /* Copy in the address of the DHCP server being used. */
+ memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ] ),
+ ( void * ) &( xDHCPData.ulDHCPServerAddress ), sizeof( xDHCPData.ulDHCPServerAddress ) );
+
+ FreeRTOS_debug_printf( ( "vDHCPProcess: reply %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );
+ iptraceSENDING_DHCP_REQUEST();
+
+ if( FreeRTOS_sendto( xDHCPData.xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( DHCPMessage_t ) + xOptionsLength ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 )
+ {
+ /* The packet was not successfully queued for sending and must be
+ returned to the stack. */
+ FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvSendDHCPDiscover( void )
+{
+uint8_t *pucUDPPayloadBuffer;
+struct freertos_sockaddr xAddress;
+static const uint8_t ucDHCPDiscoverOptions[] =
+{
+ /* Do not change the ordering without also changing dhcpCLIENT_IDENTIFIER_OFFSET. */
+ dhcpIPv4_MESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_DISCOVER, /* Message type option. */
+ dhcpIPv4_CLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */
+ dhcpIPv4_PARAMETER_REQUEST_OPTION_CODE, 3, dhcpIPv4_SUBNET_MASK_OPTION_CODE, dhcpIPv4_GATEWAY_OPTION_CODE, dhcpIPv4_DNS_SERVER_OPTIONS_CODE, /* Parameter request option. */
+ dhcpOPTION_END_BYTE
+};
+size_t xOptionsLength = sizeof( ucDHCPDiscoverOptions );
+
+ pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, ( uint8_t ) dhcpREQUEST_OPCODE, ucDHCPDiscoverOptions, &xOptionsLength );
+
+ FreeRTOS_debug_printf( ( "vDHCPProcess: discover\n" ) );
+ iptraceSENDING_DHCP_DISCOVER();
+
+ if( FreeRTOS_sendto( xDHCPData.xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( DHCPMessage_t ) + xOptionsLength ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 )
+ {
+ /* The packet was not successfully queued for sending and must be
+ returned to the stack. */
+ FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
+ }
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+
+ static void prvPrepareLinkLayerIPLookUp( void )
+ {
+ uint8_t ucLinkLayerIPAddress[ 2 ];
+
+ /* After DHCP has failed to answer, prepare everything to start
+ trying-out LinkLayer IP-addresses, using the random method. */
+ xDHCPData.xDHCPTxTime = xTaskGetTickCount();
+
+ ucLinkLayerIPAddress[ 0 ] = ( uint8_t )1 + ( uint8_t )( ipconfigRAND32() % 0xFDu ); /* get value 1..254 for IP-address 3rd byte of IP address to try. */
+ ucLinkLayerIPAddress[ 1 ] = ( uint8_t )1 + ( uint8_t )( ipconfigRAND32() % 0xFDu ); /* get value 1..254 for IP-address 4th byte of IP address to try. */
+
+ xNetworkAddressing.ulGatewayAddress = FreeRTOS_htonl( 0xA9FE0203 );
+
+ /* prepare xDHCPData with data to test. */
+ xDHCPData.ulOfferedIPAddress =
+ FreeRTOS_inet_addr_quick( LINK_LAYER_ADDRESS_0, LINK_LAYER_ADDRESS_1, ucLinkLayerIPAddress[ 0 ], ucLinkLayerIPAddress[ 1 ] );
+
+ xDHCPData.ulLeaseTime = dhcpDEFAULT_LEASE_TIME; /* don't care about lease time. just put anything. */
+
+ xNetworkAddressing.ulNetMask =
+ FreeRTOS_inet_addr_quick( LINK_LAYER_NETMASK_0, LINK_LAYER_NETMASK_1, LINK_LAYER_NETMASK_2, LINK_LAYER_NETMASK_3 );
+
+ /* DHCP completed. The IP address can now be used, and the
+ timer set to the lease timeout time. */
+ *ipLOCAL_IP_ADDRESS_POINTER = xDHCPData.ulOfferedIPAddress;
+
+ /* Setting the 'local' broadcast address, something like 192.168.1.255' */
+ xNetworkAddressing.ulBroadcastAddress = ( xDHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask;
+
+ /* Close socket to ensure packets don't queue on it. not needed anymore as DHCP failed. but still need timer for ARP testing. */
+ vSocketClose( xDHCPData.xDHCPSocket );
+ xDHCPData.xDHCPSocket = NULL;
+ xDHCPData.xDHCPTxPeriod = pdMS_TO_TICKS( 3000ul + ( ipconfigRAND32() & 0x3fful ) ); /* do ARP test every (3 + 0-1024mS) seconds. */
+
+ xARPHadIPClash = pdFALSE; /* reset flag that shows if have ARP clash. */
+ vARPSendGratuitous();
+ }
+
+#endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
+/*-----------------------------------------------------------*/
+
+#endif /* ipconfigUSE_DHCP != 0 */
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c
new file mode 100644
index 000000000..34fffab5a
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c
@@ -0,0 +1,1228 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "list.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_DNS.h"
+#include "NetworkBufferManagement.h"
+#include "NetworkInterface.h"
+#include "IPTraceMacroDefaults.h"
+
+/* Exclude the entire file if DNS is not enabled. */
+#if( ipconfigUSE_DNS != 0 )
+
+#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
+ #define dnsDNS_PORT 0x3500u
+ #define dnsONE_QUESTION 0x0100u
+ #define dnsOUTGOING_FLAGS 0x0001u /* Standard query. */
+ #define dnsRX_FLAGS_MASK 0x0f80u /* The bits of interest in the flags field of incoming DNS messages. */
+ #define dnsEXPECTED_RX_FLAGS 0x0080u /* Should be a response, without any errors. */
+#else
+ #define dnsDNS_PORT 0x0035u
+ #define dnsONE_QUESTION 0x0001u
+ #define dnsOUTGOING_FLAGS 0x0100u /* Standard query. */
+ #define dnsRX_FLAGS_MASK 0x800fu /* The bits of interest in the flags field of incoming DNS messages. */
+ #define dnsEXPECTED_RX_FLAGS 0x8000u /* Should be a response, without any errors. */
+
+#endif /* ipconfigBYTE_ORDER */
+
+/* The maximum number of times a DNS request should be sent out if a response
+is not received, before giving up. */
+#ifndef ipconfigDNS_REQUEST_ATTEMPTS
+ #define ipconfigDNS_REQUEST_ATTEMPTS 5
+#endif
+
+/* If the top two bits in the first character of a name field are set then the
+name field is an offset to the string, rather than the string itself. */
+#define dnsNAME_IS_OFFSET ( ( uint8_t ) 0xc0 )
+
+/* NBNS flags. */
+#define dnsNBNS_FLAGS_RESPONSE 0x8000u
+#define dnsNBNS_FLAGS_OPCODE_MASK 0x7800u
+#define dnsNBNS_FLAGS_OPCODE_QUERY 0x0000u
+#define dnsNBNS_FLAGS_OPCODE_REGISTRATION 0x2800u
+
+/* Host types. */
+#define dnsTYPE_A_HOST 0x0001u
+#define dnsCLASS_IN 0x0001u
+
+/* LLMNR constants. */
+#define dnsLLMNR_TTL_VALUE 300000u
+#define dnsLLMNR_FLAGS_IS_REPONSE 0x8000u
+
+/* NBNS constants. */
+#define dnsNBNS_TTL_VALUE 3600u /* 1 hour valid */
+#define dnsNBNS_TYPE_NET_BIOS 0x0020u
+#define dnsNBNS_CLASS_IN 0x0001u
+#define dnsNBNS_NAME_FLAGS 0x6000u
+#define dnsNBNS_ENCODED_NAME_LENGTH 32
+
+/* If the queried NBNS name matches with the device's name,
+the query will be responded to with these flags: */
+#define dnsNBNS_QUERY_RESPONSE_FLAGS 0x8500u
+
+/*
+ * Create a socket and bind it to the standard DNS port number. Return the
+ * the created socket - or NULL if the socket could not be created or bound.
+ */
+static Socket_t prvCreateDNSSocket( void );
+
+/*
+ * Create the DNS message in the zero copy buffer passed in the first parameter.
+ */
+static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier );
+
+/*
+ * Simple routine that jumps over the NAME field of a resource record.
+ */
+static uint8_t *prvSkipNameField( uint8_t *pucByte );
+
+/*
+ * Process a response packet from a DNS server.
+ */
+static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, TickType_t xIdentifier );
+
+/*
+ * Prepare and send a message to a DNS server. 'xReadTimeOut_ms' will be passed as
+ * zero, in case the user has supplied a call-back function.
+ */
+static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms );
+
+/*
+ * The NBNS and the LLMNR protocol share this reply function.
+ */
+#if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )
+ static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength );
+#endif
+
+#if( ipconfigUSE_NBNS == 1 )
+ static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, uint32_t ulIPAddress );
+#endif /* ipconfigUSE_NBNS */
+
+#if( ipconfigUSE_DNS_CACHE == 1 )
+ static uint8_t *prvReadNameField( uint8_t *pucByte, char *pcName, BaseType_t xLen );
+ static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, BaseType_t xLookUp );
+
+ typedef struct xDNS_CACHE_TABLE_ROW
+ {
+ uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */
+ char pcName[ipconfigDNS_CACHE_NAME_LENGTH]; /* The name of the host */
+ uint8_t ucAge; /* A value that is periodically decremented but can also be refreshed by active communication. The ARP cache entry is removed if the value reaches zero. */
+ } DNSCacheRow_t;
+
+ static DNSCacheRow_t xDNSCache[ ipconfigDNS_CACHE_ENTRIES ];
+#endif /* ipconfigUSE_DNS_CACHE == 1 */
+
+#if( ipconfigUSE_LLMNR == 1 )
+ const MACAddress_t xLLMNR_MacAdress = { { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfc } };
+#endif /* ipconfigUSE_LLMNR == 1 */
+
+/*-----------------------------------------------------------*/
+
+#include "pack_struct_start.h"
+struct xDNSMessage
+{
+ uint16_t usIdentifier;
+ uint16_t usFlags;
+ uint16_t usQuestions;
+ uint16_t usAnswers;
+ uint16_t usAuthorityRRs;
+ uint16_t usAdditionalRRs;
+}
+#include "pack_struct_end.h"
+typedef struct xDNSMessage DNSMessage_t;
+
+/* A DNS query consists of a header, as described in 'struct xDNSMessage'
+It is followed by 1 or more queries, each one consisting of a name and a tail,
+with two fields: type and class
+*/
+#include "pack_struct_start.h"
+struct xDNSTail
+{
+ uint16_t usType;
+ uint16_t usClass;
+}
+#include "pack_struct_end.h"
+typedef struct xDNSTail DNSTail_t;
+
+#if( ipconfigUSE_LLMNR == 1 )
+
+ #include "pack_struct_start.h"
+ struct xLLMNRAnswer
+ {
+ uint8_t ucNameCode;
+ uint8_t ucNameOffset; /* The name is not repeated in the answer, only the offset is given with "0xc0 <offs>" */
+ uint16_t usType;
+ uint16_t usClass;
+ uint32_t ulTTL;
+ uint16_t usDataLength;
+ uint32_t ulIPAddress;
+ }
+ #include "pack_struct_end.h"
+ typedef struct xLLMNRAnswer LLMNRAnswer_t;
+
+#endif /* ipconfigUSE_LLMNR == 1 */
+
+#if( ipconfigUSE_NBNS == 1 )
+
+ #include "pack_struct_start.h"
+ struct xNBNSRequest
+ {
+ uint16_t usRequestId;
+ uint16_t usFlags;
+ uint16_t ulRequestCount;
+ uint16_t usAnswerRSS;
+ uint16_t usAuthRSS;
+ uint16_t usAdditionalRSS;
+ uint8_t ucNameSpace;
+ uint8_t ucName[ dnsNBNS_ENCODED_NAME_LENGTH ];
+ uint8_t ucNameZero;
+ uint16_t usType;
+ uint16_t usClass;
+ }
+ #include "pack_struct_end.h"
+ typedef struct xNBNSRequest NBNSRequest_t;
+
+ #include "pack_struct_start.h"
+ struct xNBNSAnswer
+ {
+ uint16_t usType;
+ uint16_t usClass;
+ uint32_t ulTTL;
+ uint16_t usDataLength;
+ uint16_t usNbFlags; /* NetBIOS flags 0x6000 : IP-address, big-endian */
+ uint32_t ulIPAddress;
+ }
+ #include "pack_struct_end.h"
+ typedef struct xNBNSAnswer NBNSAnswer_t;
+
+#endif /* ipconfigUSE_NBNS == 1 */
+
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_DNS_CACHE == 1 )
+ uint32_t FreeRTOS_dnslookup( const char *pcHostName )
+ {
+ uint32_t ulIPAddress = 0UL;
+ prvProcessDNSCache( pcHostName, &ulIPAddress, pdTRUE );
+ return ulIPAddress;
+ }
+#endif /* ipconfigUSE_DNS_CACHE == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigDNS_USE_CALLBACKS != 0 )
+
+ typedef struct xDNS_Callback {
+ TickType_t xRemaningTime; /* Timeout in ms */
+ FOnDNSEvent pCallbackFunction; /* Function to be called when the address has been found or when a timeout has beeen reached */
+ TimeOut_t xTimeoutState;
+ void *pvSearchID;
+ struct xLIST_ITEM xListItem;
+ char pcName[ 1 ];
+ } DNSCallback_t;
+
+ static List_t xCallbackList;
+
+ /* Define FreeRTOS_gethostbyname() as a normal blocking call. */
+ uint32_t FreeRTOS_gethostbyname( const char *pcHostName )
+ {
+ return FreeRTOS_gethostbyname_a( pcHostName, ( FOnDNSEvent ) NULL, ( void* )NULL, 0 );
+ }
+ /*-----------------------------------------------------------*/
+
+ /* Initialise the list of call-back structures. */
+ void vDNSInitialise( void );
+ void vDNSInitialise( void )
+ {
+ vListInitialise( &xCallbackList );
+ }
+ /*-----------------------------------------------------------*/
+
+ /* Iterate through the list of call-back structures and remove
+ old entries which have reached a timeout.
+ As soon as the list hase become empty, the DNS timer will be stopped
+ In case pvSearchID is supplied, the user wants to cancel a DNS request
+ */
+ void vDNSCheckCallBack( void *pvSearchID );
+ void vDNSCheckCallBack( void *pvSearchID )
+ {
+ const ListItem_t *pxIterator;
+ const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList );
+
+ vTaskSuspendAll();
+ {
+ for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
+ pxIterator != ( const ListItem_t * ) xEnd;
+ )
+ {
+ DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+ /* Move to the next item because we might remove this item */
+ pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
+ if( ( pvSearchID != NULL ) && ( pvSearchID == pxCallback->pvSearchID ) )
+ {
+ uxListRemove( &pxCallback->xListItem );
+ vPortFree( pxCallback );
+ }
+ else if( xTaskCheckForTimeOut( &pxCallback->xTimeoutState, &pxCallback->xRemaningTime ) != pdFALSE )
+ {
+ pxCallback->pCallbackFunction( pxCallback->pcName, pxCallback->pvSearchID, 0 );
+ uxListRemove( &pxCallback->xListItem );
+ vPortFree( ( void * ) pxCallback );
+ }
+ }
+ }
+ xTaskResumeAll();
+
+ if( listLIST_IS_EMPTY( &xCallbackList ) )
+ {
+ vIPSetDnsTimerEnableState( pdFALSE );
+ }
+ }
+ /*-----------------------------------------------------------*/
+
+ void FreeRTOS_gethostbyname_cancel( void *pvSearchID )
+ {
+ /* _HT_ Should better become a new API call to have the IP-task remove the callback */
+ vDNSCheckCallBack( pvSearchID );
+ }
+ /*-----------------------------------------------------------*/
+
+ /* FreeRTOS_gethostbyname_a() was called along with callback parameters.
+ Store them in a list for later reference. */
+ static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier );
+ static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier )
+ {
+ size_t lLength = strlen( pcHostName );
+ DNSCallback_t *pxCallback = ( DNSCallback_t * )pvPortMalloc( sizeof( *pxCallback ) + lLength );
+
+ /* Translate from ms to number of clock ticks. */
+ xTimeout /= portTICK_PERIOD_MS;
+ if( pxCallback != NULL )
+ {
+ if( listLIST_IS_EMPTY( &xCallbackList ) )
+ {
+ /* This is the first one, start the DNS timer to check for timeouts */
+ vIPReloadDNSTimer( FreeRTOS_min_uint32( 1000U, xTimeout ) );
+ }
+ strcpy( pxCallback->pcName, pcHostName );
+ pxCallback->pCallbackFunction = pCallbackFunction;
+ pxCallback->pvSearchID = pvSearchID;
+ pxCallback->xRemaningTime = xTimeout;
+ vTaskSetTimeOutState( &pxCallback->xTimeoutState );
+ listSET_LIST_ITEM_OWNER( &( pxCallback->xListItem ), ( void* ) pxCallback );
+ listSET_LIST_ITEM_VALUE( &( pxCallback->xListItem ), xIdentifier );
+ vTaskSuspendAll();
+ {
+ vListInsertEnd( &xCallbackList, &pxCallback->xListItem );
+ }
+ xTaskResumeAll();
+ }
+ }
+ /*-----------------------------------------------------------*/
+
+ /* A DNS reply was received, see if there is any matching entry and
+ call the handler. */
+ static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress );
+ static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress )
+ {
+ const ListItem_t *pxIterator;
+ const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList );
+
+ vTaskSuspendAll();
+ {
+ for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
+ pxIterator != ( const ListItem_t * ) xEnd;
+ pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
+ {
+ if( listGET_LIST_ITEM_VALUE( pxIterator ) == xIdentifier )
+ {
+ DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+ pxCallback->pCallbackFunction( pcName, pxCallback->pvSearchID, ulIPAddress );
+ uxListRemove( &pxCallback->xListItem );
+ vPortFree( pxCallback );
+ if( listLIST_IS_EMPTY( &xCallbackList ) )
+ {
+ vIPSetDnsTimerEnableState( pdFALSE );
+ }
+ break;
+ }
+ }
+ }
+ xTaskResumeAll();
+ }
+
+#endif /* ipconfigDNS_USE_CALLBACKS != 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigDNS_USE_CALLBACKS == 0 )
+uint32_t FreeRTOS_gethostbyname( const char *pcHostName )
+#else
+uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName, FOnDNSEvent pCallback, void *pvSearchID, TickType_t xTimeout )
+#endif
+{
+uint32_t ulIPAddress = 0UL;
+static uint16_t usIdentifier = 0u;
+TickType_t xReadTimeOut_ms = 1200U;
+/* Generate a unique identifier for this query. Keep it in a local variable
+ as gethostbyname() may be called from different threads */
+TickType_t xIdentifier = ( TickType_t )usIdentifier++;
+
+ /* If a DNS cache is used then check the cache before issuing another DNS
+ request. */
+ #if( ipconfigUSE_DNS_CACHE == 1 )
+ {
+ ulIPAddress = FreeRTOS_dnslookup( pcHostName );
+ if( ulIPAddress != 0 )
+ {
+ FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) );
+ }
+ else
+ {
+ /* prvGetHostByName will be called to start a DNS lookup. */
+ }
+ }
+ #endif /* ipconfigUSE_DNS_CACHE == 1 */
+
+ #if( ipconfigDNS_USE_CALLBACKS != 0 )
+ {
+ if( pCallback != NULL )
+ {
+ if( ulIPAddress == 0UL )
+ {
+ /* The user has provided a callback function, so do not block on recvfrom() */
+ xReadTimeOut_ms = 0;
+ vDNSSetCallBack( pcHostName, pvSearchID, pCallback, xTimeout, ( TickType_t ) xIdentifier );
+ }
+ else
+ {
+ /* The IP address is known, do the call-back now. */
+ pCallback( pcHostName, pvSearchID, ulIPAddress );
+ }
+ }
+ }
+ #endif
+
+ if( ulIPAddress == 0UL)
+ {
+ ulIPAddress = prvGetHostByName( pcHostName, xIdentifier, xReadTimeOut_ms );
+ }
+
+ return ulIPAddress;
+}
+/*-----------------------------------------------------------*/
+
+static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms )
+{
+struct freertos_sockaddr xAddress;
+Socket_t xDNSSocket;
+uint32_t ulIPAddress = 0UL;
+uint8_t *pucUDPPayloadBuffer;
+static uint32_t ulAddressLength;
+BaseType_t xAttempt;
+int32_t lBytes;
+size_t xPayloadLength, xExpectedPayloadLength;
+TickType_t xWriteTimeOut_ms = 100U;
+
+#if( ipconfigUSE_LLMNR == 1 )
+ BaseType_t bHasDot = pdFALSE;
+#endif /* ipconfigUSE_LLMNR == 1 */
+
+ /* If LLMNR is being used then determine if the host name includes a '.' -
+ if not then LLMNR can be used as the lookup method. */
+ #if( ipconfigUSE_LLMNR == 1 )
+ {
+ const char *pucPtr;
+ for( pucPtr = pcHostName; *pucPtr; pucPtr++ )
+ {
+ if( *pucPtr == '.' )
+ {
+ bHasDot = pdTRUE;
+ break;
+ }
+ }
+ }
+ #endif /* ipconfigUSE_LLMNR == 1 */
+
+ /* Two is added at the end for the count of characters in the first
+ subdomain part and the string end byte. */
+ xExpectedPayloadLength = sizeof( DNSMessage_t ) + strlen( pcHostName ) + sizeof( uint16_t ) + sizeof( uint16_t ) + 2u;
+
+ xDNSSocket = prvCreateDNSSocket();
+
+ if( xDNSSocket != NULL )
+ {
+ FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xWriteTimeOut_ms, sizeof( TickType_t ) );
+ FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xReadTimeOut_ms, sizeof( TickType_t ) );
+
+ for( xAttempt = 0; xAttempt < ipconfigDNS_REQUEST_ATTEMPTS; xAttempt++ )
+ {
+ /* Get a buffer. This uses a maximum delay, but the delay will be
+ capped to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value
+ still needs to be tested. */
+ pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xExpectedPayloadLength, portMAX_DELAY );
+
+ if( pucUDPPayloadBuffer != NULL )
+ {
+ /* Create the message in the obtained buffer. */
+ xPayloadLength = prvCreateDNSMessage( pucUDPPayloadBuffer, pcHostName, xIdentifier );
+
+ iptraceSENDING_DNS_REQUEST();
+
+ /* Obtain the DNS server address. */
+ FreeRTOS_GetAddressConfiguration( NULL, NULL, NULL, &ulIPAddress );
+
+ /* Send the DNS message. */
+#if( ipconfigUSE_LLMNR == 1 )
+ if( bHasDot == pdFALSE )
+ {
+ /* Use LLMNR addressing. */
+ ( ( DNSMessage_t * ) pucUDPPayloadBuffer) -> usFlags = 0;
+ xAddress.sin_addr = ipLLMNR_IP_ADDR; /* Is in network byte order. */
+ xAddress.sin_port = FreeRTOS_ntohs( ipLLMNR_PORT );
+ }
+ else
+#endif
+ {
+ /* Use DNS server. */
+ xAddress.sin_addr = ulIPAddress;
+ xAddress.sin_port = dnsDNS_PORT;
+ }
+
+ ulIPAddress = 0UL;
+
+ if( FreeRTOS_sendto( xDNSSocket, pucUDPPayloadBuffer, xPayloadLength, FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) != 0 )
+ {
+ /* Wait for the reply. */
+ lBytes = FreeRTOS_recvfrom( xDNSSocket, &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xAddress, &ulAddressLength );
+
+ if( lBytes > 0 )
+ {
+ /* The reply was received. Process it. */
+ ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, xIdentifier );
+
+ /* Finished with the buffer. The zero copy interface
+ is being used, so the buffer must be freed by the
+ task. */
+ FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );
+
+ if( ulIPAddress != 0UL )
+ {
+ /* All done. */
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* The message was not sent so the stack will not be
+ releasing the zero copy - it must be released here. */
+ FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );
+ }
+ }
+ }
+
+ /* Finished with the socket. */
+ FreeRTOS_closesocket( xDNSSocket );
+ }
+
+ return ulIPAddress;
+}
+/*-----------------------------------------------------------*/
+
+static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier )
+{
+DNSMessage_t *pxDNSMessageHeader;
+uint8_t *pucStart, *pucByte;
+DNSTail_t *pxTail;
+static const DNSMessage_t xDefaultPartDNSHeader =
+{
+ 0, /* The identifier will be overwritten. */
+ dnsOUTGOING_FLAGS, /* Flags set for standard query. */
+ dnsONE_QUESTION, /* One question is being asked. */
+ 0, /* No replies are included. */
+ 0, /* No authorities. */
+ 0 /* No additional authorities. */
+};
+
+ /* Copy in the const part of the header. */
+ memcpy( ( void * ) pucUDPPayloadBuffer, ( void * ) &xDefaultPartDNSHeader, sizeof( xDefaultPartDNSHeader ) );
+
+ /* Write in a unique identifier. */
+ pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
+ pxDNSMessageHeader->usIdentifier = ( uint16_t ) xIdentifier;
+
+ /* Create the resource record at the end of the header. First
+ find the end of the header. */
+ pucStart = pucUDPPayloadBuffer + sizeof( xDefaultPartDNSHeader );
+
+ /* Leave a gap for the first length bytes. */
+ pucByte = pucStart + 1;
+
+ /* Copy in the host name. */
+ strcpy( ( char * ) pucByte, pcHostName );
+
+ /* Mark the end of the string. */
+ pucByte += strlen( pcHostName );
+ *pucByte = 0x00u;
+
+ /* Walk the string to replace the '.' characters with byte counts.
+ pucStart holds the address of the byte count. Walking the string
+ starts after the byte count position. */
+ pucByte = pucStart;
+
+ do
+ {
+ pucByte++;
+
+ while( ( *pucByte != 0x00 ) && ( *pucByte != '.' ) )
+ {
+ pucByte++;
+ }
+
+ /* Fill in the byte count, then move the pucStart pointer up to
+ the found byte position. */
+ *pucStart = ( uint8_t ) ( ( uint32_t ) pucByte - ( uint32_t ) pucStart );
+ ( *pucStart )--;
+
+ pucStart = pucByte;
+
+ } while( *pucByte != 0x00 );
+
+ /* Finish off the record. */
+
+ pxTail = (DNSTail_t *)( pucByte + 1 );
+
+ vSetField16( pxTail, DNSTail_t, usType, dnsTYPE_A_HOST ); /* Type A: host */
+ vSetField16( pxTail, DNSTail_t, usClass, dnsCLASS_IN ); /* 1: Class IN */
+
+ /* Return the total size of the generated message, which is the space from
+ the last written byte to the beginning of the buffer. */
+ return ( ( uint32_t ) pucByte - ( uint32_t ) pucUDPPayloadBuffer + 1 ) + sizeof( *pxTail );
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_DNS_CACHE == 1 )
+
+ static uint8_t *prvReadNameField( uint8_t *pucByte, char *pcName, BaseType_t xLen )
+ {
+ BaseType_t xNameLen = 0;
+ /* Determine if the name is the fully coded name, or an offset to the name
+ elsewhere in the message. */
+ if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )
+ {
+ /* Jump over the two byte offset. */
+ pucByte += sizeof( uint16_t );
+
+ }
+ else
+ {
+ /* pucByte points to the full name. Walk over the string. */
+ while( *pucByte != 0x00 )
+ {
+ BaseType_t xCount;
+ if( xNameLen && xNameLen < xLen - 1 )
+ pcName[xNameLen++] = '.';
+ for( xCount = *(pucByte++); xCount--; pucByte++ )
+ {
+ if( xNameLen < xLen - 1 )
+ pcName[xNameLen++] = *( ( char * ) pucByte );
+ }
+ }
+
+ pucByte++;
+ }
+
+ return pucByte;
+ }
+#endif /* ipconfigUSE_DNS_CACHE == 1 */
+/*-----------------------------------------------------------*/
+
+static uint8_t *prvSkipNameField( uint8_t *pucByte )
+{
+ /* Determine if the name is the fully coded name, or an offset to the name
+ elsewhere in the message. */
+ if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )
+ {
+ /* Jump over the two byte offset. */
+ pucByte += sizeof( uint16_t );
+
+ }
+ else
+ {
+ /* pucByte points to the full name. Walk over the string. */
+ while( *pucByte != 0x00 )
+ {
+ /* The number of bytes to jump for each name section is stored in the byte
+ before the name section. */
+ pucByte += ( *pucByte + 1 );
+ }
+
+ pucByte++;
+ }
+
+ return pucByte;
+}
+/*-----------------------------------------------------------*/
+
+uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );
+DNSMessage_t *pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
+
+ prvParseDNSReply( pucUDPPayloadBuffer, ( uint32_t ) pxDNSMessageHeader->usIdentifier );
+
+ /* The packet was not consumed. */
+ return pdFAIL;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_NBNS == 1 )
+
+ uint32_t ulNBNSHandlePacket (NetworkBufferDescriptor_t *pxNetworkBuffer )
+ {
+ UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
+ uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( *pxUDPPacket );
+
+ prvTreatNBNS( pucUDPPayloadBuffer, pxUDPPacket->xIPHeader.ulSourceIPAddress );
+
+ /* The packet was not consumed. */
+ return pdFAIL;
+ }
+
+#endif /* ipconfigUSE_NBNS */
+/*-----------------------------------------------------------*/
+
+static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, TickType_t xIdentifier )
+{
+DNSMessage_t *pxDNSMessageHeader;
+uint32_t ulIPAddress = 0UL;
+#if( ipconfigUSE_LLMNR == 1 )
+ char *pcRequestedName = NULL;
+#endif
+uint8_t *pucByte;
+uint16_t x, usDataLength, usQuestions;
+#if( ipconfigUSE_LLMNR == 1 )
+ uint16_t usType = 0, usClass = 0;
+#endif
+#if( ipconfigUSE_DNS_CACHE == 1 )
+ char pcName[128] = ""; /*_RB_ What is the significance of 128? Probably too big to go on the stack for a small MCU but don't know how else it could be made re-entrant. Might be necessary. */
+#endif
+
+ pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
+
+ if( pxDNSMessageHeader->usIdentifier == ( uint16_t ) xIdentifier )
+ {
+ /* Start at the first byte after the header. */
+ pucByte = pucUDPPayloadBuffer + sizeof( DNSMessage_t );
+
+ /* Skip any question records. */
+ usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions );
+ for( x = 0; x < usQuestions; x++ )
+ {
+ #if( ipconfigUSE_LLMNR == 1 )
+ {
+ if( x == 0 )
+ {
+ pcRequestedName = ( char * ) pucByte;
+ }
+ }
+ #endif
+
+#if( ipconfigUSE_DNS_CACHE == 1 )
+ if( x == 0 )
+ {
+ pucByte = prvReadNameField( pucByte, pcName, sizeof( pcName ) );
+ }
+ else
+#endif /* ipconfigUSE_DNS_CACHE */
+ {
+ /* Skip the variable length pcName field. */
+ pucByte = prvSkipNameField( pucByte );
+ }
+
+ #if( ipconfigUSE_LLMNR == 1 )
+ {
+ /* usChar2u16 returns value in host endianness. */
+ usType = usChar2u16( pucByte );
+ usClass = usChar2u16( pucByte + 2 );
+ }
+ #endif /* ipconfigUSE_LLMNR */
+
+ /* Skip the type and class fields. */
+ pucByte += sizeof( uint32_t );
+ }
+
+ /* Search through the answers records. */
+ pxDNSMessageHeader->usAnswers = FreeRTOS_ntohs( pxDNSMessageHeader->usAnswers );
+
+ if( ( pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK ) == dnsEXPECTED_RX_FLAGS )
+ {
+ for( x = 0; x < pxDNSMessageHeader->usAnswers; x++ )
+ {
+ pucByte = prvSkipNameField( pucByte );
+
+ /* Is the type field that of an A record? */
+ if( usChar2u16( pucByte ) == dnsTYPE_A_HOST )
+ {
+ /* This is the required record. Skip the type, class, and
+ time to live fields, plus the first byte of the data
+ length. */
+ pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) + sizeof( uint8_t ) );
+
+ /* Sanity check the data length. */
+ if( ( size_t ) *pucByte == sizeof( uint32_t ) )
+ {
+ /* Skip the second byte of the length. */
+ pucByte++;
+
+ /* Copy the IP address out of the record. */
+ memcpy( ( void * ) &ulIPAddress, ( void * ) pucByte, sizeof( uint32_t ) );
+
+ #if( ipconfigUSE_DNS_CACHE == 1 )
+ {
+ prvProcessDNSCache( pcName, &ulIPAddress, pdFALSE );
+ }
+ #endif /* ipconfigUSE_DNS_CACHE */
+ #if( ipconfigDNS_USE_CALLBACKS != 0 )
+ {
+ /* See if any asynchronous call was made to FreeRTOS_gethostbyname_a() */
+ vDNSDoCallback( ( TickType_t ) pxDNSMessageHeader->usIdentifier, pcName, ulIPAddress );
+ }
+ #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
+ }
+
+ break;
+ }
+ else
+ {
+ /* Skip the type, class and time to live fields. */
+ pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) );
+
+ /* Determine the length of the data in the field. */
+ memcpy( ( void * ) &usDataLength, ( void * ) pucByte, sizeof( uint16_t ) );
+ usDataLength = FreeRTOS_ntohs( usDataLength );
+
+ /* Jump over the data length bytes, and the data itself. */
+ pucByte += usDataLength + sizeof( uint16_t );
+ }
+ }
+ }
+#if( ipconfigUSE_LLMNR == 1 )
+ else if( ( usQuestions != ( uint16_t )0u ) && ( usType == ( uint16_t )dnsTYPE_A_HOST ) && ( usClass == ( uint16_t )dnsCLASS_IN ) )
+ {
+ /* If this is not a reply to our DNS request, it might an LLMNR
+ request. */
+ if( xApplicationDNSQueryHook ( ( pcRequestedName + 1 ) ) )
+ {
+ int16_t usLength;
+ NetworkBufferDescriptor_t *pxNewBuffer = NULL;
+ NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );
+ LLMNRAnswer_t *pxAnswer;
+
+ if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )
+ {
+ BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) +
+ sizeof( EthernetHeader_t ) + sizeof( IPHeader_t );
+
+ /* The field xDataLength was set to the length of the UDP payload.
+ The answer (reply) will be longer than the request, so the packet
+ must be duplicaed into a bigger buffer */
+ pxNetworkBuffer->xDataLength = xDataLength;
+ pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 );
+ if( pxNewBuffer != NULL )
+ {
+ BaseType_t xOffset1, xOffset2;
+
+ xOffset1 = ( BaseType_t ) ( pucByte - pucUDPPayloadBuffer );
+ xOffset2 = ( BaseType_t ) ( ( ( uint8_t * ) pcRequestedName ) - pucUDPPayloadBuffer );
+
+ pxNetworkBuffer = pxNewBuffer;
+ pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + ipUDP_PAYLOAD_OFFSET_IPv4;
+
+ pucByte = pucUDPPayloadBuffer + xOffset1;
+ pcRequestedName = ( char * ) ( pucUDPPayloadBuffer + xOffset2 );
+ pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
+
+ }
+ else
+ {
+ /* Just to indicate that the message may not be answered. */
+ pxNetworkBuffer = NULL;
+ }
+ }
+ if( pxNetworkBuffer != NULL )
+ {
+ pxAnswer = (LLMNRAnswer_t *)pucByte;
+
+ /* Leave 'usIdentifier' and 'usQuestions' untouched. */
+ vSetField16( pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE ); /* Set the response flag */
+ vSetField16( pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */
+ vSetField16( pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */
+ vSetField16( pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */
+
+ pxAnswer->ucNameCode = dnsNAME_IS_OFFSET;
+ pxAnswer->ucNameOffset = ( uint8_t )( pcRequestedName - ( char * ) pucUDPPayloadBuffer );
+
+ vSetField16( pxAnswer, LLMNRAnswer_t, usType, dnsTYPE_A_HOST ); /* Type A: host */
+ vSetField16( pxAnswer, LLMNRAnswer_t, usClass, dnsCLASS_IN ); /* 1: Class IN */
+ vSetField32( pxAnswer, LLMNRAnswer_t, ulTTL, dnsLLMNR_TTL_VALUE );
+ vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, 4 );
+ vSetField32( pxAnswer, LLMNRAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );
+
+ usLength = ( int16_t ) ( sizeof( *pxAnswer ) + ( size_t ) ( pucByte - pucUDPPayloadBuffer ) );
+
+ prvReplyDNSMessage( pxNetworkBuffer, usLength );
+
+ if( pxNewBuffer != NULL )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxNewBuffer );
+ }
+ }
+ }
+ }
+#endif /* ipconfigUSE_LLMNR == 1 */
+ }
+
+ return ulIPAddress;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_NBNS == 1 )
+
+ static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, uint32_t ulIPAddress )
+ {
+ uint16_t usFlags, usType, usClass;
+ uint8_t *pucSource, *pucTarget;
+ uint8_t ucByte;
+ uint8_t ucNBNSName[ 17 ];
+
+ usFlags = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usFlags ) );
+
+ if( ( usFlags & dnsNBNS_FLAGS_OPCODE_MASK ) == dnsNBNS_FLAGS_OPCODE_QUERY )
+ {
+ usType = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );
+ usClass = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usClass ) );
+
+ /* Not used for now */
+ ( void )usClass;
+ /* For NBNS a name is 16 bytes long, written with capitals only.
+ Make sure that the copy is terminated with a zero. */
+ pucTarget = ucNBNSName + sizeof(ucNBNSName ) - 2;
+ pucTarget[ 1 ] = '\0';
+
+ /* Start with decoding the last 2 bytes. */
+ pucSource = pucUDPPayloadBuffer + ( offsetof( NBNSRequest_t, ucName ) + ( dnsNBNS_ENCODED_NAME_LENGTH - 2 ) );
+
+ for( ;; )
+ {
+ ucByte = ( uint8_t ) ( ( ( pucSource[ 0 ] - 0x41 ) << 4 ) | ( pucSource[ 1 ] - 0x41 ) );
+
+ /* Make sure there are no trailing spaces in the name. */
+ if( ( ucByte == ' ' ) && ( pucTarget[ 1 ] == '\0' ) )
+ {
+ ucByte = '\0';
+ }
+
+ *pucTarget = ucByte;
+
+ if( pucTarget == ucNBNSName )
+ {
+ break;
+ }
+
+ pucTarget -= 1;
+ pucSource -= 2;
+ }
+
+ #if( ipconfigUSE_DNS_CACHE == 1 )
+ {
+ if( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) != 0 )
+ {
+ /* If this is a response from another device,
+ add the name to the DNS cache */
+ prvProcessDNSCache( ( char * ) ucNBNSName, &ulIPAddress, pdFALSE );
+ }
+ }
+ #else
+ {
+ /* Avoid compiler warnings. */
+ ( void ) ulIPAddress;
+ }
+ #endif /* ipconfigUSE_DNS_CACHE */
+
+ if( ( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) == 0 ) &&
+ ( usType == dnsNBNS_TYPE_NET_BIOS ) &&
+ ( xApplicationDNSQueryHook( ( const char * ) ucNBNSName ) != pdFALSE ) )
+ {
+ uint16_t usLength;
+ DNSMessage_t *pxMessage;
+ NBNSAnswer_t *pxAnswer;
+
+ /* Someone is looking for a device with ucNBNSName,
+ prepare a positive reply. */
+ NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );
+
+ if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )
+ {
+ NetworkBufferDescriptor_t *pxNewBuffer;
+ BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) +
+
+ sizeof( EthernetHeader_t ) + sizeof( IPHeader_t );
+
+ /* The field xDataLength was set to the length of the UDP payload.
+ The answer (reply) will be longer than the request, so the packet
+ must be duplicated into a bigger buffer */
+ pxNetworkBuffer->xDataLength = xDataLength;
+ pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 );
+ if( pxNewBuffer != NULL )
+ {
+ pucUDPPayloadBuffer = pxNewBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );
+ pxNetworkBuffer = pxNewBuffer;
+ }
+ else
+ {
+ /* Just prevent that a reply will be sent */
+ pxNetworkBuffer = NULL;
+ }
+ }
+
+ /* Should not occur: pucUDPPayloadBuffer is part of a xNetworkBufferDescriptor */
+ if( pxNetworkBuffer != NULL )
+ {
+ pxMessage = (DNSMessage_t *)pucUDPPayloadBuffer;
+
+ /* As the fields in the structures are not word-aligned, we have to
+ copy the values byte-by-byte using macro's vSetField16() and vSetField32() */
+ vSetField16( pxMessage, DNSMessage_t, usFlags, dnsNBNS_QUERY_RESPONSE_FLAGS ); /* 0x8500 */
+ vSetField16( pxMessage, DNSMessage_t, usQuestions, 0 );
+ vSetField16( pxMessage, DNSMessage_t, usAnswers, 1 );
+ vSetField16( pxMessage, DNSMessage_t, usAuthorityRRs, 0 );
+ vSetField16( pxMessage, DNSMessage_t, usAdditionalRRs, 0 );
+
+ pxAnswer = (NBNSAnswer_t *)( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );
+
+ vSetField16( pxAnswer, NBNSAnswer_t, usType, usType ); /* Type */
+ vSetField16( pxAnswer, NBNSAnswer_t, usClass, dnsNBNS_CLASS_IN ); /* Class */
+ vSetField32( pxAnswer, NBNSAnswer_t, ulTTL, dnsNBNS_TTL_VALUE );
+ vSetField16( pxAnswer, NBNSAnswer_t, usDataLength, 6 ); /* 6 bytes including the length field */
+ vSetField16( pxAnswer, NBNSAnswer_t, usNbFlags, dnsNBNS_NAME_FLAGS );
+ vSetField32( pxAnswer, NBNSAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );
+
+ usLength = ( uint16_t ) ( offsetof( NBNSRequest_t, usType ) + sizeof( NBNSAnswer_t ) );
+
+ prvReplyDNSMessage( pxNetworkBuffer, usLength );
+ }
+ }
+ }
+ }
+
+#endif /* ipconfigUSE_NBNS */
+/*-----------------------------------------------------------*/
+
+static Socket_t prvCreateDNSSocket( void )
+{
+static Socket_t xSocket = NULL;
+struct freertos_sockaddr xAddress;
+BaseType_t xReturn;
+TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 );
+
+ /* This must be the first time this function has been called. Create
+ the socket. */
+ xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
+
+ /* Auto bind the port. */
+ xAddress.sin_port = 0u;
+ xReturn = FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );
+
+ /* Check the bind was successful, and clean up if not. */
+ if( xReturn != 0 )
+ {
+ FreeRTOS_closesocket( xSocket );
+ xSocket = NULL;
+ }
+ else
+ {
+ /* Set the send and receive timeouts. */
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
+ }
+
+ return xSocket;
+}
+/*-----------------------------------------------------------*/
+
+#if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )
+
+ static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength )
+ {
+ UDPPacket_t *pxUDPPacket;
+ IPHeader_t *pxIPHeader;
+ UDPHeader_t *pxUDPHeader;
+
+ pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer;
+ pxIPHeader = &pxUDPPacket->xIPHeader;
+ pxUDPHeader = &pxUDPPacket->xUDPHeader;
+ /* HT: started using defines like 'ipSIZE_OF_xxx' */
+ pxIPHeader->usLength = FreeRTOS_htons( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER );
+ /* HT:endian: should not be translated, copying from packet to packet */
+ pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
+ pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
+ pxIPHeader->ucTimeToLive = ipconfigUDP_TIME_TO_LIVE;
+ pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
+ usPacketIdentifier++;
+ pxUDPHeader->usLength = FreeRTOS_htons( lNetLength + ipSIZE_OF_UDP_HEADER );
+ vFlip_16( pxUDPPacket->xUDPHeader.usSourcePort, pxUDPPacket->xUDPHeader.usDestinationPort );
+
+ #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
+ {
+ /* calculate the IP header checksum */
+ pxIPHeader->usHeaderChecksum = 0x00;
+ pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
+ pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
+
+ /* calculate the UDP checksum for outgoing package */
+ usGenerateProtocolChecksum( ( uint8_t* ) pxUDPPacket, pdTRUE );
+ }
+ #endif
+
+ /* Important: tell NIC driver how many bytes must be sent */
+ pxNetworkBuffer->xDataLength = ( size_t ) ( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER + ipSIZE_OF_ETH_HEADER );
+
+ /* This function will fill in the eth addresses and send the packet */
+ vReturnEthernetFrame( pxNetworkBuffer, pdFALSE );
+ }
+
+#endif /* ipconfigUSE_NBNS == 1 || ipconfigUSE_LLMNR == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_DNS_CACHE == 1 )
+
+ static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, BaseType_t xLookUp )
+ {
+ BaseType_t x;
+ BaseType_t xFound = pdFALSE;
+ static BaseType_t xFreeEntry = 0;
+
+ /* For each entry in the DNS cache table. */
+ for( x = 0; x < ipconfigDNS_CACHE_ENTRIES; x++ )
+ {
+ if( xDNSCache[ x ].pcName[ 0 ] == 0 )
+ {
+ break;
+ }
+
+ if( strncmp( xDNSCache[ x ].pcName, pcName, sizeof( xDNSCache[ x ].pcName ) ) == 0 )
+ {
+ /* Is this function called for a lookup or to add/update an IP address? */
+ if( xLookUp != pdFALSE )
+ {
+ *pulIP = xDNSCache[ x ].ulIPAddress;
+ }
+ else
+ {
+ xDNSCache[ x ].ulIPAddress = *pulIP;
+ }
+
+ xFound = pdTRUE;
+ break;
+ }
+ }
+
+ if( xFound == pdFALSE )
+ {
+ if( xLookUp != pdFALSE )
+ {
+ *pulIP = 0;
+ }
+ else
+ {
+ /* Called to add or update an item */
+ strncpy( xDNSCache[ xFreeEntry ].pcName, pcName, sizeof( xDNSCache[ xFreeEntry ].pcName ) );
+ xDNSCache[ xFreeEntry ].ulIPAddress = *pulIP;
+
+ xFreeEntry++;
+ if( xFreeEntry == ipconfigDNS_CACHE_ENTRIES )
+ {
+ xFreeEntry = 0;
+ }
+ }
+ }
+
+ if( ( xLookUp == 0 ) || ( *pulIP != 0 ) )
+ {
+ FreeRTOS_debug_printf( ( "prvProcessDNSCache: %s: '%s' @ %lxip\n", xLookUp ? "look-up" : "add", pcName, FreeRTOS_ntohl( *pulIP ) ) );
+ }
+ }
+
+#endif /* ipconfigUSE_DNS_CACHE */
+
+#endif /* ipconfigUSE_DNS != 0 */
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c
new file mode 100644
index 000000000..6b7ec5f36
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c
@@ -0,0 +1,2205 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* 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. */
+#define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) )
+
+/* 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( const 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. The event is initialised to "no
+ event" in case the following call exits due to a time out rather than a
+ message being received. */
+ xReceivedEvent.eEventType = eNoEvent;
+ xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep );
+
+ #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 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;
+ /* xStart keeps a copy of the last time this function was active,
+ and during every call it will be updated with xTaskGetTickCount()
+ '0' means: not yet initialised (although later '0' might be returned
+ by xTaskGetTickCount(), which is no problem). */
+ static TickType_t xStart = ( TickType_t ) 0;
+ TickType_t xTimeNow, xNextTime;
+ BaseType_t xCheckTCPSockets;
+ extern uint32_t ulNextInitialSequenceNumber;
+
+ if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0u )
+ {
+ xWillSleep = pdTRUE;
+ }
+ else
+ {
+ xWillSleep = pdFALSE;
+ }
+
+ xTimeNow = xTaskGetTickCount();
+
+ if( xStart != ( TickType_t ) 0 )
+ {
+ /* It is advised to increment the Initial Sequence Number every 4
+ microseconds which makes 250 times per ms. This will make it harder
+ for a third party to 'guess' our sequence number and 'take over'
+ a TCP connection */
+ ulNextInitialSequenceNumber += ipINITIAL_SEQUENCE_NUMBER_FACTOR * ( ( xTimeNow - xStart ) * portTICK_PERIOD_MS );
+ }
+
+ xStart = xTimeNow;
+
+ /* 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 )
+ {
+ /* 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,
+ BaseType_t xNewLength )
+{
+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( ( size_t ) xNewLength, ( TickType_t ) 0 );
+
+ if( pxNewBuffer != NULL )
+ {
+ 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. */
+ 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. */
+ vNetworkSocketsInit();
+
+ /* 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;
+ pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( ICMPHeader_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
+
+ /* 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;
+volatile eFrameProcessingResult_t eReturned; /* Volatile to prevent complier warnings when ipCONSIDER_FRAME_FOR_PROCESSING just sets it to eProcessBuffer. */
+
+ configASSERT( pxNetworkBuffer );
+
+ /* Interpret the Ethernet frame. */
+ 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. */
+ eReturned = eARPProcessPacket( ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
+ break;
+
+ case ipIPv4_FRAME_TYPE :
+ /* The Ethernet frame contains an IP packet. */
+ eReturned = prvProcessIPPacket( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer );
+ 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 (fragmentation
+ was only supported for outgoing packets, and is not currently
+ not supported at all). */
+ 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 ), 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( const IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer )
+{
+eFrameProcessingResult_t eReturn;
+const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
+UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( pxIPHeader->ucVersionHeaderLength & 0x0Fu ) << 2 );
+uint8_t ucProtocol;
+
+ 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 * ) pxIPHeader ) + uxHeaderLength;
+ /* To: the usual start of UDP/ICMP/TCP data at offset 20 from IP header */
+ uint8_t *pucTarget = ( ( uint8_t * ) pxIPHeader ) + 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;
+ }
+ /* 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 )
+ {
+ ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+ if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )
+ {
+ eReturn = prvProcessICMPPacket( pxICMPPacket );
+ }
+ }
+ #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 );
+
+ /* Note the header values required prior to the
+ checksum generation as the checksum pseudo header
+ may clobber some of these values. */
+ pxNetworkBuffer->xDataLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t );
+ /* HT:endian: fields in pxNetworkBuffer (usPort, ulIPAddress) were 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. */
+ /* HT:endian: xProcessReceivedUDPPacket wanted network order */
+ if( xProcessReceivedUDPPacket( pxNetworkBuffer, pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )
+ {
+ eReturn = eFrameConsumed;
+ }
+ }
+ 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, 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
+
+ pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer;
+ uxIPHeaderLength = ( UBaseType_t ) ( 4u * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) ); /*_RB_ Why 4? */
+ pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) );
+ ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
+
+ if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
+ {
+ 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 )
+ {
+ 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 ) )
+ {
+ 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;
+ }
+
+ 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 ),
+ ( size_t )( 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;
+}
+/*-----------------------------------------------------------*/
+
+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;
+}
+/*-----------------------------------------------------------*/
+
+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
+/*-----------------------------------------------------------*/
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c
new file mode 100644
index 000000000..e5fd643a1
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c
@@ -0,0 +1,3644 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "FreeRTOS_DNS.h"
+#include "NetworkBufferManagement.h"
+
+/* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
+port number. */
+#define socketSET_SOCKET_PORT( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
+#define socketGET_SOCKET_PORT( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
+
+/* Test if a socket it bound which means it is either included in
+xBoundUDPSocketsList or xBoundTCPSocketsList */
+#define socketSOCKET_IS_BOUND( pxSocket ) ( listLIST_ITEM_CONTAINER( & ( pxSocket )->xBoundSocketListItem ) != NULL )
+
+/* If FreeRTOS_sendto() is called on a socket that is not bound to a port
+number then, depending on the FreeRTOSIPConfig.h settings, it might be that a
+port number is automatically generated for the socket. Automatically generated
+port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and
+0xffff. */
+/* _HT_ thinks that the default of 0xc000 is pretty high */
+#if !defined( socketAUTO_PORT_ALLOCATION_START_NUMBER )
+ #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0xc000 )
+#endif
+
+/* When the automatically generated port numbers overflow, the next value used
+is not set back to socketAUTO_PORT_ALLOCATION_START_NUMBER because it is likely
+that the first few automatically generated ports will still be in use. Instead
+it is reset back to the value defined by this constant. */
+#define socketAUTO_PORT_ALLOCATION_RESET_NUMBER ( ( uint16_t ) 0xc100 )
+#define socketAUTO_PORT_ALLOCATION_MAX_NUMBER ( ( uint16_t ) 0xff00 )
+
+/* The number of octets that make up an IP address. */
+#define socketMAX_IP_ADDRESS_OCTETS 4u
+
+/* A block time of 0 simply means "don't block". */
+#define socketDONT_BLOCK ( ( TickType_t ) 0 )
+
+#if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )
+ #define ipTCP_TIMER_PERIOD_MS ( 1000 )
+#endif
+
+/* The next private port number to use when binding a client socket is stored in
+the usNextPortToUse[] array - which has either 1 or two indexes depending on
+whether TCP is being supported. */
+#if( ipconfigUSE_TCP == 1 )
+ #define socketPROTOCOL_COUNT 2
+#else
+ #define socketPROTOCOL_COUNT 1
+#endif
+
+/* Indexes into the usNextPortToUse[] array for UDP and TCP sockets
+respectively. */
+#define socketNEXT_UDP_PORT_NUMBER_INDEX 0
+#define socketNEXT_TCP_PORT_NUMBER_INDEX 1
+
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Allocate the next port number from the private allocation range.
+ * TCP and UDP each have their own series of port numbers
+ * ulProtocol is either ipPROTOCOL_UDP or ipPROTOCOL_TCP
+ */
+static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol );
+
+/*
+ * Return the list item from within pxList that has an item value of
+ * xWantedItemValue. If there is no such list item return NULL.
+ */
+static const ListItem_t * pxListFindListItemWithValue( const List_t *pxList, TickType_t xWantedItemValue );
+
+/*
+ * Return pdTRUE only if pxSocket is valid and bound, as far as can be
+ * determined.
+ */
+static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound );
+
+/*
+ * Before creating a socket, check the validity of the parameters used
+ * and find the size of the socket space, which is different for UDP and TCP
+ */
+static BaseType_t prvDetermineSocketSize( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol, size_t *pxSocketSize );
+
+#if( ipconfigUSE_TCP == 1 )
+ /*
+ * Create a txStream or a rxStream, depending on the parameter 'xIsInputStream'
+ */
+ static StreamBuffer_t *prvTCPCreateStream (FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream );
+#endif /* ipconfigUSE_TCP == 1 */
+
+#if( ipconfigUSE_TCP == 1 )
+ /*
+ * Called from FreeRTOS_send(): some checks which will be done before
+ * sending a TCP packed.
+ */
+ static int32_t prvTCPSendCheck( FreeRTOS_Socket_t *pxSocket, size_t xDataLength );
+#endif /* ipconfigUSE_TCP */
+
+#if( ipconfigUSE_TCP == 1 )
+ /*
+ * When a child socket gets closed, make sure to update the child-count of the parent
+ */
+ static void prvTCPSetSocketCount( FreeRTOS_Socket_t *pxSocketToDelete );
+#endif /* ipconfigUSE_TCP == 1 */
+
+#if( ipconfigUSE_TCP == 1 )
+ /*
+ * Called from FreeRTOS_connect(): make some checks and if allowed, send a
+ * message to the IP-task to start connecting to a remote socket
+ */
+ static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr *pxAddress );
+#endif /* ipconfigUSE_TCP */
+
+#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+
+ /* Executed by the IP-task, it will check all sockets belonging to a set */
+ static FreeRTOS_Socket_t *prvFindSelectedSocket( SocketSelect_t *pxSocketSet );
+
+#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
+/*-----------------------------------------------------------*/
+
+/* The list that contains mappings between sockets and port numbers. Accesses
+to this list must be protected by critical sections of one kind or another. */
+List_t xBoundUDPSocketsList;
+
+#if ipconfigUSE_TCP == 1
+ List_t xBoundTCPSocketsList;
+#endif /* ipconfigUSE_TCP == 1 */
+
+/* Holds the next private port number to use when binding a client socket for
+UDP, and if ipconfigUSE_TCP is set to 1, also TCP. UDP uses index
+socketNEXT_UDP_PORT_NUMBER_INDEX and TCP uses index
+socketNEXT_TCP_PORT_NUMBER_INDEX. The initial value is set to be between
+socketAUTO_PORT_ALLOCATION_RESET_NUMBER and socketAUTO_PORT_ALLOCATION_MAX_NUMBER
+when the IP stack is initialised. Note ipconfigRAND32() is used, which must be
+seeded prior to the IP task being started. */
+static uint16_t usNextPortToUse[ socketPROTOCOL_COUNT ] = { 0 };
+
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound )
+{
+BaseType_t xReturn = pdTRUE;
+
+ if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) )
+ {
+ xReturn = pdFALSE;
+ }
+ else if( ( xIsBound != pdFALSE ) && ( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE ) )
+ {
+ /* The caller expects the socket to be bound, but it isn't. */
+ xReturn = pdFALSE;
+ }
+ else if( pxSocket->ucProtocol != ( uint8_t ) xProtocol )
+ {
+ /* Socket has a wrong type (UDP != TCP). */
+ xReturn = pdFALSE;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vNetworkSocketsInit( void )
+{
+const uint32_t ulAutoPortRange = socketAUTO_PORT_ALLOCATION_MAX_NUMBER - socketAUTO_PORT_ALLOCATION_RESET_NUMBER;
+uint32_t ulRandomPort;
+
+ vListInitialise( &xBoundUDPSocketsList );
+
+ /* Determine the first anonymous UDP port number to get assigned. Give it
+ a random value in order to avoid confusion about port numbers being used
+ earlier, before rebooting the device. Start with the first auto port
+ number, then add a random offset up to a maximum of the range of numbers. */
+ ulRandomPort = socketAUTO_PORT_ALLOCATION_START_NUMBER;
+ ulRandomPort += ( ipconfigRAND32() % ulAutoPortRange );
+ usNextPortToUse[ socketNEXT_UDP_PORT_NUMBER_INDEX ] = ( uint16_t ) ulRandomPort;
+
+ #if( ipconfigUSE_TCP == 1 )
+ {
+ extern uint32_t ulNextInitialSequenceNumber;
+
+ ulNextInitialSequenceNumber = ipconfigRAND32();
+
+ /* Determine the first anonymous TCP port number to get assigned. */
+ ulRandomPort = socketAUTO_PORT_ALLOCATION_START_NUMBER;
+ ulRandomPort += ( ipconfigRAND32() % ulAutoPortRange );
+ usNextPortToUse[ socketNEXT_TCP_PORT_NUMBER_INDEX ] = ( uint16_t ) ulRandomPort;
+
+ vListInitialise( &xBoundTCPSocketsList );
+ }
+ #endif /* ipconfigUSE_TCP == 1 */
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvDetermineSocketSize( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol, size_t *pxSocketSize )
+{
+BaseType_t xReturn = pdPASS;
+FreeRTOS_Socket_t *pxSocket;
+
+ /* Asserts must not appear before it has been determined that the network
+ task is ready - otherwise the asserts will fail. */
+ if( xIPIsNetworkTaskReady() == pdFALSE )
+ {
+ xReturn = pdFAIL;
+ }
+ else
+ {
+ /* Only Ethernet is currently supported. */
+ configASSERT( xDomain == FREERTOS_AF_INET );
+
+ /* Check if the UDP socket-list has been initialised. */
+ configASSERT( listLIST_IS_INITIALISED( &xBoundUDPSocketsList ) );
+ #if( ipconfigUSE_TCP == 1 )
+ {
+ /* Check if the TCP socket-list has been initialised. */
+ configASSERT( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) );
+ }
+ #endif /* ipconfigUSE_TCP == 1 */
+
+ if( xProtocol == FREERTOS_IPPROTO_UDP )
+ {
+ if( xType != FREERTOS_SOCK_DGRAM )
+ {
+ xReturn = pdFAIL;
+ }
+ /* In case a UDP socket is created, do not allocate space for TCP data. */
+ *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xUDP );
+ }
+#if( ipconfigUSE_TCP == 1 )
+ else if( xProtocol == FREERTOS_IPPROTO_TCP )
+ {
+ if( xType != FREERTOS_SOCK_STREAM )
+ {
+ xReturn = pdFAIL;
+ }
+
+ *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xTCP );
+ }
+#endif /* ipconfigUSE_TCP == 1 */
+ else
+ {
+ xReturn = pdFAIL;
+ }
+ }
+ /* In case configASSERT() is not used */
+ ( void )xDomain;
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+/* FreeRTOS_socket() allocates and initiates a socket */
+Socket_t FreeRTOS_socket( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol )
+{
+FreeRTOS_Socket_t *pxSocket;
+size_t uxSocketSize;
+EventGroupHandle_t xEventGroup;
+Socket_t xReturn;
+
+ if( prvDetermineSocketSize( xDomain, xType, xProtocol, &uxSocketSize ) == pdFAIL )
+ {
+ xReturn = FREERTOS_INVALID_SOCKET;
+ }
+ else
+ {
+ /* Allocate the structure that will hold the socket information. The
+ size depends on the type of socket: UDP sockets need less space. A
+ define 'pvPortMallocSocket' will used to allocate the necessary space.
+ By default it points to the FreeRTOS function 'pvPortMalloc()'. */
+ pxSocket = ( FreeRTOS_Socket_t * ) pvPortMallocSocket( uxSocketSize );
+
+ if( pxSocket == NULL )
+ {
+ pxSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
+ iptraceFAILED_TO_CREATE_SOCKET();
+ }
+ else if( ( xEventGroup = xEventGroupCreate() ) == NULL )
+ {
+ vPortFreeSocket( pxSocket );
+ pxSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
+ iptraceFAILED_TO_CREATE_EVENT_GROUP();
+ }
+ else
+ {
+ /* Clear the entire space to avoid nulling individual entries. */
+ memset( pxSocket, '\0', uxSocketSize );
+
+ pxSocket->xEventGroup = xEventGroup;
+
+ /* Initialise the socket's members. The semaphore will be created
+ if the socket is bound to an address, for now the pointer to the
+ semaphore is just set to NULL to show it has not been created. */
+ if( xProtocol == FREERTOS_IPPROTO_UDP )
+ {
+ vListInitialise( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
+
+ #if( ipconfigUDP_MAX_RX_PACKETS > 0 )
+ {
+ pxSocket->u.xUDP.uxMaxPackets = ( UBaseType_t ) ipconfigUDP_MAX_RX_PACKETS;
+ }
+ #endif /* ipconfigUDP_MAX_RX_PACKETS > 0 */
+ }
+
+ vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
+ listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );
+
+ pxSocket->xReceiveBlockTime = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME;
+ pxSocket->xSendBlockTime = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME;
+ pxSocket->ucSocketOptions = ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT;
+ pxSocket->ucProtocol = ( uint8_t ) xProtocol; /* protocol: UDP or TCP */
+
+ #if( ipconfigUSE_TCP == 1 )
+ {
+ if( xProtocol == FREERTOS_IPPROTO_TCP )
+ {
+ /* StreamSize is expressed in number of bytes */
+ /* Round up buffer sizes to nearest multiple of MSS */
+ pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ipconfigTCP_MSS;
+ pxSocket->u.xTCP.uxRxStreamSize = ( size_t ) ipconfigTCP_RX_BUFFER_LENGTH;
+ pxSocket->u.xTCP.uxTxStreamSize = ( size_t ) FreeRTOS_round_up( ipconfigTCP_TX_BUFFER_LENGTH, ipconfigTCP_MSS );
+ /* Use half of the buffer size of the TCP windows */
+ #if ( ipconfigUSE_TCP_WIN == 1 )
+ {
+ pxSocket->u.xTCP.uxRxWinSize = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxRxStreamSize / 2 ) / ipconfigTCP_MSS );
+ pxSocket->u.xTCP.uxTxWinSize = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxTxStreamSize / 2 ) / ipconfigTCP_MSS );
+ }
+ #else
+ {
+ pxSocket->u.xTCP.uxRxWinSize = 1u;
+ pxSocket->u.xTCP.uxTxWinSize = 1u;
+ }
+ #endif
+ /* The above values are just defaults, and can be overridden by
+ calling FreeRTOS_setsockopt(). No buffers will be allocated until a
+ socket is connected and data is exchanged. */
+ }
+ }
+ #endif /* ipconfigUSE_TCP == 1 */
+ }
+
+ xReturn = ( Socket_t ) pxSocket;
+ }
+
+ /* Remove compiler warnings in the case the configASSERT() is not defined. */
+ ( void ) xDomain;
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+
+ SocketSet_t FreeRTOS_CreateSocketSet( void )
+ {
+ SocketSelect_t *pxSocketSet;
+
+ pxSocketSet = ( SocketSelect_t * ) pvPortMalloc( sizeof( *pxSocketSet ) );
+
+ if( pxSocketSet != NULL )
+ {
+ memset( pxSocketSet, '\0', sizeof( *pxSocketSet ) );
+ pxSocketSet->xSelectGroup = xEventGroupCreate();
+
+ if( pxSocketSet->xSelectGroup == NULL )
+ {
+ vPortFree( ( void* ) pxSocketSet );
+ pxSocketSet = NULL;
+ }
+ }
+
+ return ( SocketSet_t * ) pxSocketSet;
+ }
+
+#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+
+ void FreeRTOS_DeleteSocketSet( SocketSet_t xSocketSet )
+ {
+ SocketSelect_t *pxSocketSet = ( SocketSelect_t*) xSocketSet;
+
+ vEventGroupDelete( pxSocketSet->xSelectGroup );
+ vPortFree( ( void* ) pxSocketSet );
+ }
+
+#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+
+ /* Add a socket to a set */
+ void FreeRTOS_FD_SET( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xSelectBits )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ SocketSelect_t *pxSocketSet = ( SocketSelect_t * ) xSocketSet;
+
+ configASSERT( pxSocket != NULL );
+ configASSERT( xSocketSet != NULL );
+
+ /* Make sure we're not adding bits which are reserved for internal use,
+ such as eSELECT_CALL_IP */
+ pxSocket->xSelectBits |= ( xSelectBits & eSELECT_ALL );
+
+ if( ( pxSocket->xSelectBits & eSELECT_ALL ) != 0 )
+ {
+ /* Adding a socket to a socket set. */
+ pxSocket->pxSocketSet = ( SocketSelect_t * ) xSocketSet;
+
+ /* Now have the IP-task call vSocketSelect() to see if the set contains
+ any sockets which are 'ready' and set the proper bits.
+ By setting 'bApiCalled = false', vSocketSelect() knows that it was
+ not called from a user API */
+ pxSocketSet->bApiCalled = pdFALSE;
+ prvFindSelectedSocket( pxSocketSet );
+ }
+ }
+
+#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+ /* Clear select bits for a socket
+ If the mask becomes 0, remove the socket from the set */
+ void FreeRTOS_FD_CLR( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xSelectBits )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+
+ configASSERT( pxSocket != NULL );
+ configASSERT( xSocketSet != NULL );
+
+ pxSocket->xSelectBits &= ~( xSelectBits & eSELECT_ALL );
+ if( ( pxSocket->xSelectBits & eSELECT_ALL ) != 0 )
+ {
+ pxSocket->pxSocketSet = ( SocketSelect_t *)xSocketSet;
+ }
+ else
+ {
+ /* disconnect it from the socket set */
+ pxSocket->pxSocketSet = ( SocketSelect_t *)NULL;
+ }
+ }
+
+#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
+/*-----------------------------------------------------------*/
+
+
+#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+
+ /* Test if a socket belongs to a socket-set */
+ EventBits_t FreeRTOS_FD_ISSET( Socket_t xSocket, SocketSet_t xSocketSet )
+ {
+ EventBits_t xReturn;
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+
+ configASSERT( pxSocket != NULL );
+ configASSERT( xSocketSet != NULL );
+
+ if( xSocketSet == ( SocketSet_t ) pxSocket->pxSocketSet )
+ {
+ /* Make sure we're not adding bits which are reserved for internal
+ use. */
+ xReturn = pxSocket->xSocketBits & eSELECT_ALL;
+ }
+ else
+ {
+ xReturn = 0;
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+
+ /* The select() statement: wait for an event to occur on any of the sockets
+ included in a socket set */
+ BaseType_t FreeRTOS_select( SocketSet_t xSocketSet, TickType_t xBlockTimeTicks )
+ {
+ TimeOut_t xTimeOut;
+ TickType_t xRemainingTime;
+ SocketSelect_t *pxSocketSet = ( SocketSelect_t*) xSocketSet;
+ BaseType_t xResult;
+
+ configASSERT( xSocketSet != NULL );
+
+ /* Only in the first round, check for non-blocking */
+ xRemainingTime = xBlockTimeTicks;
+
+ /* Fetch the current time */
+ vTaskSetTimeOutState( &xTimeOut );
+
+ for( ;; )
+ {
+ /* Find a socket which might have triggered the bit
+ This function might return immediately or block for a limited time */
+ xResult = ( BaseType_t ) xEventGroupWaitBits( pxSocketSet->xSelectGroup, eSELECT_ALL, pdFALSE, pdFALSE, xRemainingTime );
+
+ #if( ipconfigSUPPORT_SIGNALS != 0 )
+ {
+ if( ( xResult & eSELECT_INTR ) != 0u )
+ {
+ xEventGroupClearBits( pxSocketSet->xSelectGroup, eSELECT_INTR );
+ FreeRTOS_debug_printf( ( "FreeRTOS_select: interrupted\n" ) );
+ break;
+ }
+ }
+ #endif /* ipconfigSUPPORT_SIGNALS */
+
+ /* Have the IP-task find the socket which had an event */
+ pxSocketSet->bApiCalled = pdTRUE;
+ prvFindSelectedSocket( pxSocketSet );
+
+ xResult = ( BaseType_t ) xEventGroupGetBits( pxSocketSet->xSelectGroup );
+
+ if( xResult != 0 )
+ {
+ break;
+ }
+
+ /* Has the timeout been reached? */
+ if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
+ {
+ break;
+ }
+ }
+
+ return xResult;
+ }
+
+#endif /* ipconfigSUPPORT_SELECT_FUNCTION */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+
+ /* Send a message to the IP-task to have it check all sockets belonging to
+ 'pxSocketSet' */
+ static FreeRTOS_Socket_t *prvFindSelectedSocket( SocketSelect_t *pxSocketSet )
+ {
+ IPStackEvent_t xSelectEvent;
+ FreeRTOS_Socket_t *xReturn;
+
+ xSelectEvent.eEventType = eSocketSelectEvent;
+ xSelectEvent.pvData = ( void * ) pxSocketSet;
+
+ /* while the IP-task works on the request, the API will block on
+ 'eSELECT_CALL_IP'. So clear it first. */
+ xEventGroupClearBits( pxSocketSet->xSelectGroup, eSELECT_CALL_IP );
+
+ /* Now send the socket select event */
+ if( xSendEventStructToIPTask( &xSelectEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
+ {
+ /* Oops, we failed to wake-up the IP task. No use to wait for it. */
+ FreeRTOS_debug_printf( ( "prvFindSelectedSocket: failed\n" ) );
+ xReturn = NULL;
+ }
+ else
+ {
+ /* As soon as the IP-task is ready, it will set 'eSELECT_CALL_IP' to
+ wakeup the calling API */
+ xEventGroupWaitBits( pxSocketSet->xSelectGroup, eSELECT_CALL_IP, pdTRUE, pdFALSE, portMAX_DELAY );
+
+ /* Return 'pxSocket' which is set by the IP-task */
+ xReturn = pxSocketSet->pxSocket;
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
+/*-----------------------------------------------------------*/
+
+/*
+ * FreeRTOS_recvfrom: receive data from a bound socket
+ * In this library, the function can only be used with connectionsless sockets
+ * (UDP)
+ */
+int32_t FreeRTOS_recvfrom( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )
+{
+BaseType_t lPacketCount = 0;
+NetworkBufferDescriptor_t *pxNetworkBuffer;
+FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+TickType_t xRemainingTime = ( TickType_t ) 0; /* Obsolete assignment, but some compilers output a warning if its not done. */
+BaseType_t xTimed = pdFALSE;
+TimeOut_t xTimeOut;
+int32_t lReturn;
+EventBits_t xEventBits = ( EventBits_t ) 0;
+
+ if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_UDP, pdTRUE ) == pdFALSE )
+ {
+ return -pdFREERTOS_ERRNO_EINVAL;
+ }
+
+ lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
+
+ /* The function prototype is designed to maintain the expected Berkeley
+ sockets standard, but this implementation does not use all the parameters. */
+ ( void ) pxSourceAddressLength;
+
+ while( lPacketCount == 0 )
+ {
+ if( xTimed == pdFALSE )
+ {
+ /* Check to see if the socket is non blocking on the first
+ iteration. */
+ xRemainingTime = pxSocket->xReceiveBlockTime;
+
+ if( xRemainingTime == ( TickType_t ) 0 )
+ {
+ #if( ipconfigSUPPORT_SIGNALS != 0 )
+ {
+ /* Just check for the interrupt flag. */
+ xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_INTR,
+ pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
+ }
+ #endif /* ipconfigSUPPORT_SIGNALS */
+ break;
+ }
+
+ if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 )
+ {
+ break;
+ }
+
+ /* To ensure this part only executes once. */
+ xTimed = pdTRUE;
+
+ /* Fetch the current time. */
+ vTaskSetTimeOutState( &xTimeOut );
+ }
+
+ /* Wait for arrival of data. While waiting, the IP-task may set the
+ 'eSOCKET_RECEIVE' bit in 'xEventGroup', if it receives data for this
+ socket, thus unblocking this API call. */
+ xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_RECEIVE | eSOCKET_INTR,
+ pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
+
+ #if( ipconfigSUPPORT_SIGNALS != 0 )
+ {
+ if( ( xEventBits & eSOCKET_INTR ) != 0 )
+ {
+ if( ( xEventBits & eSOCKET_RECEIVE ) != 0 )
+ {
+ /* Shouldn't have cleared the eSOCKET_RECEIVE flag. */
+ xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_RECEIVE );
+ }
+ break;
+ }
+ }
+ #else
+ {
+ ( void ) xEventBits;
+ }
+ #endif /* ipconfigSUPPORT_SIGNALS */
+
+ lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
+
+ if( lPacketCount != 0 )
+ {
+ break;
+ }
+
+ /* Has the timeout been reached ? */
+ if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) )
+ {
+ break;
+ }
+ } /* while( lPacketCount == 0 ) */
+
+ if( lPacketCount != 0 )
+ {
+ taskENTER_CRITICAL();
+ {
+ /* The owner of the list item is the network buffer. */
+ pxNetworkBuffer = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
+
+ if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 )
+ {
+ /* Remove the network buffer from the list of buffers waiting to
+ be processed by the socket. */
+ uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ /* The returned value is the data length, which may have been capped to
+ the receive buffer size. */
+ lReturn = ( int32_t ) pxNetworkBuffer->xDataLength;
+
+ if( pxSourceAddress != NULL )
+ {
+ pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
+ pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
+ }
+
+ if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 )
+ {
+ /* The zero copy flag is not set. Truncate the length if it won't
+ fit in the provided buffer. */
+ if( lReturn > ( int32_t ) xBufferLength )
+ {
+ iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - lReturn ) );
+ lReturn = ( int32_t )xBufferLength;
+ }
+
+ /* Copy the received data into the provided buffer, then release the
+ network buffer. */
+ memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ), ( size_t )lReturn );
+
+ if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ }
+ }
+ else
+ {
+ /* The zero copy flag was set. pvBuffer is not a buffer into which
+ the received data can be copied, but a pointer that must be set to
+ point to the buffer in which the received data has already been
+ placed. */
+ *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ) );
+ }
+
+ }
+#if( ipconfigSUPPORT_SIGNALS != 0 )
+ else if( ( xEventBits & eSOCKET_INTR ) != 0 )
+ {
+ lReturn = -pdFREERTOS_ERRNO_EINTR;
+ iptraceRECVFROM_INTERRUPTED();
+ }
+#endif /* ipconfigSUPPORT_SIGNALS */
+ else
+ {
+ lReturn = -pdFREERTOS_ERRNO_EWOULDBLOCK;
+ iptraceRECVFROM_TIMEOUT();
+ }
+
+ return lReturn;
+}
+/*-----------------------------------------------------------*/
+
+int32_t FreeRTOS_sendto( Socket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, BaseType_t xFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )
+{
+NetworkBufferDescriptor_t *pxNetworkBuffer;
+IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
+TimeOut_t xTimeOut;
+TickType_t xTicksToWait;
+int32_t lReturn = 0;
+FreeRTOS_Socket_t *pxSocket;
+
+ pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+
+ /* The function prototype is designed to maintain the expected Berkeley
+ sockets standard, but this implementation does not use all the
+ parameters. */
+ ( void ) xDestinationAddressLength;
+ configASSERT( pvBuffer );
+
+ if( xTotalDataLength <= ( size_t ) ipMAX_UDP_PAYLOAD_LENGTH )
+ {
+ /* If the socket is not already bound to an address, bind it now.
+ Passing NULL as the address parameter tells FreeRTOS_bind() to select
+ the address to bind to. */
+ if( ( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE ) ||
+ ( FreeRTOS_bind( xSocket, NULL, 0u ) == 0 ) )
+ {
+ xTicksToWait = pxSocket->xSendBlockTime;
+
+ #if( ipconfigUSE_CALLBACKS != 0 )
+ {
+ if( xIsCallingFromIPTask() != pdFALSE )
+ {
+ /* If this send function is called from within a call-back
+ handler it may not block, otherwise chances would be big to
+ get a deadlock: the IP-task waiting for itself. */
+ xTicksToWait = ( TickType_t )0;
+ }
+ }
+ #endif /* ipconfigUSE_CALLBACKS */
+
+ if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 )
+ {
+ xTicksToWait = ( TickType_t ) 0;
+ }
+
+ if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 )
+ {
+ /* Zero copy is not set, so obtain a network buffer into
+ which the payload will be copied. */
+ vTaskSetTimeOutState( &xTimeOut );
+
+ /* Block until a buffer becomes available, or until a
+ timeout has been reached */
+ pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xTotalDataLength + sizeof( UDPPacket_t ), xTicksToWait );
+
+ if( pxNetworkBuffer != NULL )
+ {
+ memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ), ( void * ) pvBuffer, xTotalDataLength );
+
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
+ {
+ /* The entire block time has been used up. */
+ xTicksToWait = ( TickType_t ) 0;
+ }
+ }
+ }
+ else
+ {
+ /* When zero copy is used, pvBuffer is a pointer to the
+ payload of a buffer that has already been obtained from the
+ stack. Obtain the network buffer pointer from the buffer. */
+ pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( (void*)pvBuffer );
+ }
+
+ if( pxNetworkBuffer != NULL )
+ {
+ pxNetworkBuffer->xDataLength = xTotalDataLength;
+ pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
+ pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_PORT( pxSocket );
+ pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
+
+ /* The socket options are passed to the IP layer in the
+ space that will eventually get used by the Ethernet header. */
+ pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
+
+ /* Tell the networking task that the packet needs sending. */
+ xStackTxEvent.pvData = pxNetworkBuffer;
+
+ /* Ask the IP-task to send this packet */
+ if( xSendEventStructToIPTask( &xStackTxEvent, xTicksToWait ) == pdPASS )
+ {
+ /* The packet was successfully sent to the IP task. */
+ lReturn = ( int32_t ) xTotalDataLength;
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ {
+ if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleSent ) )
+ {
+ pxSocket->u.xUDP.pxHandleSent( (Socket_t *)pxSocket, xTotalDataLength );
+ }
+ }
+ #endif /* ipconfigUSE_CALLBACKS */
+ }
+ else
+ {
+ /* If the buffer was allocated in this function, release
+ it. */
+ if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ }
+ iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
+ }
+ }
+ else
+ {
+ /* If errno was available, errno would be set to
+ FREERTOS_ENOPKTS. As it is, the function must return the
+ number of transmitted bytes, so the calling function knows
+ how much data was actually sent. */
+ iptraceNO_BUFFER_FOR_SENDTO();
+ }
+ }
+ else
+ {
+ iptraceSENDTO_SOCKET_NOT_BOUND();
+ }
+ }
+ else
+ {
+ /* The data is longer than the available buffer space. */
+ iptraceSENDTO_DATA_TOO_LONG();
+ }
+
+ return lReturn;
+} /* Tested */
+/*-----------------------------------------------------------*/
+
+/*
+ * FreeRTOS_bind() : binds a sockt to a local port number. If port 0 is
+ * provided, a system provided port number will be assigned. This function can
+ * be used for both UDP and TCP sockets. The actual binding will be performed
+ * by the IP-task to avoid mutual access to the bound-socket-lists
+ * (xBoundUDPSocketsList or xBoundTCPSocketsList).
+ */
+BaseType_t FreeRTOS_bind( Socket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength )
+{
+IPStackEvent_t xBindEvent;
+FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+BaseType_t xReturn = 0;
+
+ ( void ) xAddressLength;
+
+ if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) )
+ {
+ xReturn = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ /* Once a socket is bound to a port, it can not be bound to a different
+ port number */
+ else if( socketSOCKET_IS_BOUND( pxSocket) != pdFALSE )
+ {
+ /* The socket is already bound. */
+ FreeRTOS_debug_printf( ( "vSocketBind: Socket already bound to %d\n", pxSocket->usLocalPort ) );
+ xReturn = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else
+ {
+ /* Prepare a messages to the IP-task in order to perform the binding.
+ The desired port number will be passed in usLocalPort. */
+ xBindEvent.eEventType = eSocketBindEvent;
+ xBindEvent.pvData = ( void * ) xSocket;
+ if( pxAddress != NULL )
+ {
+ pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port );
+ }
+ else
+ {
+ /* Caller wants to bind to a random port number. */
+ pxSocket->usLocalPort = 0u;
+ }
+
+ /* portMAX_DELAY is used as a the time-out parameter, as binding *must*
+ succeed before the socket can be used. _RB_ The use of an infinite
+ block time needs be changed as it could result in the task hanging. */
+ if( xSendEventStructToIPTask( &xBindEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
+ {
+ /* Failed to wake-up the IP-task, no use to wait for it */
+ FreeRTOS_debug_printf( ( "FreeRTOS_bind: send event failed\n" ) );
+ xReturn = -pdFREERTOS_ERRNO_ECANCELED;
+ }
+ else
+ {
+ /* The IP-task will set the 'eSOCKET_BOUND' bit when it has done its
+ job. */
+ xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_BOUND, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, portMAX_DELAY );
+ if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
+ {
+ xReturn = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ }
+ }
+
+ return xReturn;
+}
+
+/*
+ * vSocketBind(): internal version of bind() that should not be called directly.
+ * 'xInternal' is used for TCP sockets only: it allows to have several
+ * (connected) child sockets bound to the same server port.
+ */
+BaseType_t vSocketBind( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr * pxAddress, size_t uxAddressLength, BaseType_t xInternal )
+{
+BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
+List_t *pxSocketList;
+#if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
+ struct freertos_sockaddr xAddress;
+#endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
+
+#if( ipconfigUSE_TCP == 1 )
+ if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ pxSocketList = &xBoundTCPSocketsList;
+ }
+ else
+#endif /* ipconfigUSE_TCP == 1 */
+ {
+ pxSocketList = &xBoundUDPSocketsList;
+ }
+
+ /* The function prototype is designed to maintain the expected Berkeley
+ sockets standard, but this implementation does not use all the parameters. */
+ ( void ) uxAddressLength;
+
+ configASSERT( pxSocket );
+ configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );
+
+ #if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
+ {
+ /* pxAddress will be NULL if sendto() was called on a socket without the
+ socket being bound to an address. In this case, automatically allocate
+ an address to the socket. There is a very tiny chance that the allocated
+ port will already be in use - if that is the case, then the check below
+ [pxListFindListItemWithValue()] will result in an error being returned. */
+ if( pxAddress == NULL )
+ {
+ pxAddress = &xAddress;
+ /* For now, put it to zero, will be assigned later */
+ pxAddress->sin_port = 0u;
+ }
+ }
+ #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
+
+ /* Sockets must be bound before calling FreeRTOS_sendto() if
+ ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
+ configASSERT( pxAddress );
+
+ if( pxAddress != NULL )
+ {
+ if( pxAddress->sin_port == 0u )
+ {
+ pxAddress->sin_port = prvGetPrivatePortNumber( ( BaseType_t ) pxSocket->ucProtocol );
+ }
+
+ /* If vSocketBind() is called from the API FreeRTOS_bind() it has been
+ confirmed that the socket was not yet bound to a port. If it is called
+ from the IP-task, no such check is necessary. */
+
+ /* Check to ensure the port is not already in use. If the bind is
+ called internally, a port MAY be used by more than one socket. */
+ if( ( ( xInternal == pdFALSE ) || ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) ) &&
+ ( pxListFindListItemWithValue( pxSocketList, ( TickType_t ) pxAddress->sin_port ) != NULL ) )
+ {
+ FreeRTOS_debug_printf( ( "vSocketBind: %sP port %d in use\n",
+ pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ? "TC" : "UD",
+ FreeRTOS_ntohs( pxAddress->sin_port ) ) );
+ xReturn = -pdFREERTOS_ERRNO_EADDRINUSE;
+ }
+ else
+ {
+ /* Allocate the port number to the socket.
+ This macro will set 'xBoundSocketListItem->xItemValue' */
+ socketSET_SOCKET_PORT( pxSocket, pxAddress->sin_port );
+
+ /* And also store it in a socket field 'usLocalPort' in host-byte-order,
+ mostly used for logging and debugging purposes */
+ pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port );
+
+ /* Add the socket to the list of bound ports. */
+ {
+ /* If the network driver can iterate through 'xBoundUDPSocketsList',
+ by calling xPortHasUDPSocket() then the IP-task must temporarily
+ suspend the scheduler to keep the list in a consistent state. */
+ #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
+ {
+ vTaskSuspendAll();
+ }
+ #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
+
+ /* Add the socket to 'xBoundUDPSocketsList' or 'xBoundTCPSocketsList' */
+ vListInsertEnd( pxSocketList, &( pxSocket->xBoundSocketListItem ) );
+
+ #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
+ {
+ xTaskResumeAll();
+ }
+ #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
+ }
+ }
+ }
+ else
+ {
+ xReturn = -pdFREERTOS_ERRNO_EADDRNOTAVAIL;
+ FreeRTOS_debug_printf( ( "vSocketBind: Socket no addr\n" ) );
+ }
+
+ if( xReturn != 0 )
+ {
+ iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
+ }
+
+ return xReturn;
+} /* Tested */
+/*-----------------------------------------------------------*/
+
+/*
+ * Close a socket and free the allocated space
+ * In case of a TCP socket: the connection will not be closed automatically
+ * Subsequent messages for the closed socket will be responded to with a RST
+ * The IP-task will actually close the socket, after receiving a 'eSocketCloseEvent' message
+ */
+BaseType_t FreeRTOS_closesocket( Socket_t xSocket )
+{
+BaseType_t xResult;
+#if( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 )
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * )xSocket;
+#endif
+IPStackEvent_t xCloseEvent;
+xCloseEvent.eEventType = eSocketCloseEvent;
+xCloseEvent.pvData = ( void * ) xSocket;
+
+ if( ( xSocket == NULL ) || ( xSocket == FREERTOS_INVALID_SOCKET ) )
+ {
+ xResult = 0;
+ }
+ else
+ {
+ #if( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) )
+ {
+ if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ /* Make sure that IP-task won't call the user callback's anymore */
+ pxSocket->u.xTCP.pxHandleConnected = NULL;
+ pxSocket->u.xTCP.pxHandleReceive = NULL;
+ pxSocket->u.xTCP.pxHandleSent = NULL;
+ }
+ }
+ #endif /* ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) ) */
+
+ /* Let the IP task close the socket to keep it synchronised with the
+ packet handling. */
+
+ /* Note when changing the time-out value below, it must be checked who is calling
+ this function. If it is called by the IP-task, a deadlock could occur.
+ The IP-task would only call it in case of a user call-back */
+ if( xSendEventStructToIPTask( &xCloseEvent, ( TickType_t ) 0 ) == pdFAIL )
+ {
+ FreeRTOS_debug_printf( ( "FreeRTOS_closesocket: failed\n" ) );
+ xResult = -1;
+ }
+ else
+ {
+ xResult = 1;
+ }
+ }
+
+ return xResult;
+}
+
+/* This is the internal version of FreeRTOS_closesocket()
+ * It will be called by the IPtask only to avoid problems with synchronicity
+ */
+void *vSocketClose( FreeRTOS_Socket_t *pxSocket )
+{
+NetworkBufferDescriptor_t *pxNetworkBuffer;
+
+ #if( ipconfigUSE_TCP == 1 )
+ {
+ /* For TCP: clean up a little more. */
+ if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ #if( ipconfigUSE_TCP_WIN == 1 )
+ {
+ if( pxSocket->u.xTCP.pxAckMessage != NULL )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
+ }
+ /* Free the resources which were claimed by the tcpWin member */
+ vTCPWindowDestroy( &pxSocket->u.xTCP.xTCPWindow );
+ }
+ #endif /* ipconfigUSE_TCP_WIN */
+
+ /* Free the input and output streams */
+ if( pxSocket->u.xTCP.rxStream != NULL )
+ {
+ vPortFreeLarge( pxSocket->u.xTCP.rxStream );
+ }
+
+ if( pxSocket->u.xTCP.txStream != NULL )
+ {
+ vPortFreeLarge( pxSocket->u.xTCP.txStream );
+ }
+
+ /* In case this is a child socket, make sure the child-count of the
+ parent socket is decreased. */
+ prvTCPSetSocketCount( pxSocket );
+ }
+ }
+ #endif /* ipconfigUSE_TCP == 1 */
+
+ /* Socket must be unbound first, to ensure no more packets are queued on
+ it. */
+ if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
+ {
+ /* If the network driver can iterate through 'xBoundUDPSocketsList',
+ by calling xPortHasUDPSocket(), then the IP-task must temporarily
+ suspend the scheduler to keep the list in a consistent state. */
+ #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
+ {
+ vTaskSuspendAll();
+ }
+ #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
+
+ uxListRemove( &( pxSocket->xBoundSocketListItem ) );
+
+ #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
+ {
+ xTaskResumeAll();
+ }
+ #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
+ }
+
+ /* Now the socket is not bound the list of waiting packets can be
+ drained. */
+ if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
+ {
+ while( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U )
+ {
+ pxNetworkBuffer = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
+ uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ }
+ }
+
+ if( pxSocket->xEventGroup )
+ {
+ vEventGroupDelete( pxSocket->xEventGroup );
+ }
+
+ #if( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 )
+ {
+ if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ FreeRTOS_debug_printf( ( "FreeRTOS_closesocket[%u to %lxip:%u]: buffers %lu socks %lu\n",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.ulRemoteIP,
+ pxSocket->u.xTCP.usRemotePort,
+ uxGetNumberOfFreeNetworkBuffers(),
+ listCURRENT_LIST_LENGTH( &xBoundTCPSocketsList ) ) );
+ }
+ }
+ #endif /* ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
+
+ /* Anf finally, after all resources have been freed, free the socket space */
+ vPortFreeSocket( pxSocket );
+
+ return 0;
+} /* Tested */
+
+/*-----------------------------------------------------------*/
+
+#if ipconfigUSE_TCP == 1
+
+ /*
+ * When a child socket gets closed, make sure to update the child-count of the
+ * parent. When a listening parent socket is closed, make sure no child-sockets
+ * keep a pointer to it.
+ */
+ static void prvTCPSetSocketCount( FreeRTOS_Socket_t *pxSocketToDelete )
+ {
+ const ListItem_t *pxIterator;
+ const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList );
+ FreeRTOS_Socket_t *pxOtherSocket;
+ uint16_t usLocalPort = pxSocketToDelete->usLocalPort;
+
+ for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
+ pxIterator != ( const ListItem_t * ) pxEnd;
+ pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
+ {
+ pxOtherSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+ if( ( pxOtherSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) &&
+ ( pxOtherSocket->usLocalPort == usLocalPort ) &&
+ ( pxOtherSocket->u.xTCP.usChildCount ) )
+ {
+ pxOtherSocket->u.xTCP.usChildCount--;
+ FreeRTOS_debug_printf( ( "Lost: Socket %u now has %u / %u child%s\n",
+ pxOtherSocket->usLocalPort,
+ pxOtherSocket->u.xTCP.usChildCount,
+ pxOtherSocket->u.xTCP.usBacklog,
+ pxOtherSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );
+ break;
+ }
+ }
+ }
+
+#endif /* ipconfigUSE_TCP == 1 */
+
+/*-----------------------------------------------------------*/
+
+BaseType_t FreeRTOS_setsockopt( Socket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength )
+{
+/* The standard Berkeley function returns 0 for success. */
+BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
+BaseType_t lOptionValue;
+FreeRTOS_Socket_t *pxSocket;
+
+ pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+
+ /* The function prototype is designed to maintain the expected Berkeley
+ sockets standard, but this implementation does not use all the parameters. */
+ ( void ) lLevel;
+ ( void ) xOptionLength;
+
+ configASSERT( xSocket );
+
+ switch( lOptionName )
+ {
+ case FREERTOS_SO_RCVTIMEO :
+ /* Receive time out. */
+ pxSocket->xReceiveBlockTime = *( ( TickType_t * ) pvOptionValue );
+ xReturn = 0;
+ break;
+
+ case FREERTOS_SO_SNDTIMEO :
+ pxSocket->xSendBlockTime = *( ( TickType_t * ) pvOptionValue );
+ if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
+ {
+ /* The send time out is capped for the reason stated in the
+ comments where ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined
+ in FreeRTOSIPConfig.h (assuming an official configuration file
+ is being used. */
+ if( pxSocket->xSendBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
+ {
+ pxSocket->xSendBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
+ }
+ }
+ else
+ {
+ /* For TCP socket, it isn't necessary to limit the blocking time
+ because the FreeRTOS_send() function does not wait for a network
+ buffer to become available. */
+ }
+ xReturn = 0;
+ break;
+ #if( ipconfigUDP_MAX_RX_PACKETS > 0 )
+ case FREERTOS_SO_UDP_MAX_RX_PACKETS:
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP )
+ {
+ break; /* will return -pdFREERTOS_ERRNO_EINVAL */
+ }
+ pxSocket->u.xUDP.uxMaxPackets = *( ( UBaseType_t * ) pvOptionValue );
+ xReturn = 0;
+ break;
+ #endif /* ipconfigUDP_MAX_RX_PACKETS */
+
+ case FREERTOS_SO_UDPCKSUM_OUT :
+ /* Turn calculating of the UDP checksum on/off for this socket. */
+ lOptionValue = ( BaseType_t ) pvOptionValue;
+
+ if( lOptionValue == 0 )
+ {
+ pxSocket->ucSocketOptions &= ( uint8_t ) ~FREERTOS_SO_UDPCKSUM_OUT;
+ }
+ else
+ {
+ pxSocket->ucSocketOptions |= ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT;
+ }
+ xReturn = 0;
+ break;
+
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ #if( ipconfigUSE_TCP == 1 )
+ case FREERTOS_SO_TCP_CONN_HANDLER: /* Set a callback for (dis)connection events */
+ case FREERTOS_SO_TCP_RECV_HANDLER: /* Install a callback for receiving TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
+ case FREERTOS_SO_TCP_SENT_HANDLER: /* Install a callback for sending TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
+ #endif /* ipconfigUSE_TCP */
+ case FREERTOS_SO_UDP_RECV_HANDLER: /* Install a callback for receiving UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
+ case FREERTOS_SO_UDP_SENT_HANDLER: /* Install a callback for sending UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
+ {
+ #if( ipconfigUSE_TCP == 1 )
+ {
+ UBaseType_t uxProtocol;
+ if( ( lOptionName == FREERTOS_SO_UDP_RECV_HANDLER ) ||
+ ( lOptionName == FREERTOS_SO_UDP_SENT_HANDLER ) )
+ {
+ uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_UDP;
+ }
+ else
+ {
+ uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_TCP;
+ }
+
+ if( pxSocket->ucProtocol != ( uint8_t ) uxProtocol )
+ {
+ break; /* will return -pdFREERTOS_ERRNO_EINVAL */
+ }
+ }
+ #else
+ {
+ /* No need to check if the socket has the right
+ protocol, because only UDP socket can be created. */
+ }
+ #endif /* ipconfigUSE_TCP */
+
+ switch( lOptionName )
+ {
+ #if ipconfigUSE_TCP == 1
+ case FREERTOS_SO_TCP_CONN_HANDLER:
+ pxSocket->u.xTCP.pxHandleConnected = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPConnected;
+ break;
+ case FREERTOS_SO_TCP_RECV_HANDLER:
+ pxSocket->u.xTCP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPReceive;
+ break;
+ case FREERTOS_SO_TCP_SENT_HANDLER:
+ pxSocket->u.xTCP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPSent;
+ break;
+ #endif /* ipconfigUSE_TCP */
+ case FREERTOS_SO_UDP_RECV_HANDLER:
+ pxSocket->u.xUDP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPReceive;
+ break;
+ case FREERTOS_SO_UDP_SENT_HANDLER:
+ pxSocket->u.xUDP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPSent;
+ break;
+ default:
+ break;
+ }
+ }
+
+ xReturn = 0;
+ break;
+ #endif /* ipconfigUSE_CALLBACKS */
+
+ #if( ipconfigUSE_TCP != 0 )
+ #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 )
+ /* Each socket has a semaphore on which the using task normally
+ sleeps. */
+ case FREERTOS_SO_SET_SEMAPHORE:
+ {
+ pxSocket->pxUserSemaphore = *( ( SemaphoreHandle_t * ) pvOptionValue );
+ }
+ xReturn = 0;
+ break;
+ #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
+ case FREERTOS_SO_SNDBUF: /* Set the size of the send buffer, in units of MSS (TCP only) */
+ case FREERTOS_SO_RCVBUF: /* Set the size of the receive buffer, in units of MSS (TCP only) */
+ {
+ uint32_t ulNewValue;
+
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ FreeRTOS_debug_printf( ( "Set SO_%sBUF: wrong socket type\n",
+ ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
+ break; /* will return -pdFREERTOS_ERRNO_EINVAL */
+ }
+
+ if( ( ( lOptionName == FREERTOS_SO_SNDBUF ) && ( pxSocket->u.xTCP.txStream != NULL ) ) ||
+ ( ( lOptionName == FREERTOS_SO_RCVBUF ) && ( pxSocket->u.xTCP.rxStream != NULL ) ) )
+ {
+ FreeRTOS_debug_printf( ( "Set SO_%sBUF: buffer already created\n",
+ ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
+ break; /* will return -pdFREERTOS_ERRNO_EINVAL */
+ }
+
+ ulNewValue = *( ( uint32_t * ) pvOptionValue );
+
+ if( lOptionName == FREERTOS_SO_SNDBUF )
+ {
+ /* Round up to nearest MSS size */
+ ulNewValue = FreeRTOS_round_up( ulNewValue, ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
+ pxSocket->u.xTCP.uxTxStreamSize = ulNewValue;
+ }
+ else
+ {
+ pxSocket->u.xTCP.uxRxStreamSize = ulNewValue;
+ }
+ }
+ xReturn = 0;
+ break;
+
+ case FREERTOS_SO_WIN_PROPERTIES: /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */
+ {
+ WinProperties_t* pxProps;
+
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: wrong socket type\n" ) );
+ break; /* will return -pdFREERTOS_ERRNO_EINVAL */
+ }
+
+ if( ( pxSocket->u.xTCP.txStream != NULL ) || ( pxSocket->u.xTCP.rxStream != NULL ) )
+ {
+ FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: buffer already created\n" ) );
+ break; /* will return -pdFREERTOS_ERRNO_EINVAL */
+ }
+
+ pxProps = ( ( WinProperties_t * ) pvOptionValue );
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDBUF, &( pxProps->lTxBufSize ), sizeof( pxProps->lTxBufSize ) );
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVBUF, &( pxProps->lRxBufSize ), sizeof( pxProps->lRxBufSize ) );
+ #if( ipconfigUSE_TCP_WIN == 1 )
+ {
+ pxSocket->u.xTCP.uxRxWinSize = ( uint32_t )pxProps->lRxWinSize; /* Fixed value: size of the TCP reception window */
+ pxSocket->u.xTCP.uxTxWinSize = ( uint32_t )pxProps->lTxWinSize; /* Fixed value: size of the TCP transmit window */
+ }
+ #else
+ {
+ pxSocket->u.xTCP.uxRxWinSize = 1u;
+ pxSocket->u.xTCP.uxTxWinSize = 1u;
+ }
+ #endif
+
+ /* In case the socket has already initialised its tcpWin,
+ adapt the window size parameters */
+ if( pxSocket->u.xTCP.xTCPWindow.u.bits.bHasInit != pdFALSE_UNSIGNED )
+ {
+ pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength = pxSocket->u.xTCP.uxRxWinSize * pxSocket->u.xTCP.usInitMSS;
+ pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength = pxSocket->u.xTCP.uxTxWinSize * pxSocket->u.xTCP.usInitMSS;
+ }
+ }
+
+ xReturn = 0;
+ break;
+
+ case FREERTOS_SO_REUSE_LISTEN_SOCKET: /* If true, the server-socket will turn into a connected socket */
+ {
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ break; /* will return -pdFREERTOS_ERRNO_EINVAL */
+ }
+ if( *( ( BaseType_t * ) pvOptionValue ) != 0 )
+ {
+ pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED;
+ }
+ else
+ {
+ pxSocket->u.xTCP.bits.bReuseSocket = pdFALSE_UNSIGNED;
+ }
+ }
+ xReturn = 0;
+ break;
+
+ case FREERTOS_SO_CLOSE_AFTER_SEND: /* As soon as the last byte has been transmitted, finalise the connection */
+ {
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ break; /* will return -pdFREERTOS_ERRNO_EINVAL */
+ }
+
+ if( *( ( BaseType_t * ) pvOptionValue ) != 0 )
+ {
+ pxSocket->u.xTCP.bits.bCloseAfterSend = pdTRUE_UNSIGNED;
+ }
+ else
+ {
+ pxSocket->u.xTCP.bits.bCloseAfterSend = pdFALSE_UNSIGNED;
+ }
+ }
+ xReturn = 0;
+ break;
+
+ case FREERTOS_SO_SET_FULL_SIZE: /* Refuse to send packets smaller than MSS */
+ {
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ break; /* will return -pdFREERTOS_ERRNO_EINVAL */
+ }
+
+ if( *( ( BaseType_t * ) pvOptionValue ) != 0 )
+ {
+ pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdTRUE_UNSIGNED;
+ }
+ else
+ {
+ pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdFALSE_UNSIGNED;
+ }
+
+ if( ( pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize == pdFALSE_UNSIGNED ) &&
+ ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) &&
+ ( FreeRTOS_outstanding( pxSocket ) != 0 ) )
+ {
+ pxSocket->u.xTCP.usTimeout = 1u; /* to set/clear bSendFullSize */
+ xSendEventToIPTask( eTCPTimerEvent );
+ }
+ }
+ xReturn = 0;
+ break;
+
+ case FREERTOS_SO_STOP_RX: /* Refuse to receive more packts */
+ {
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ break; /* will return -pdFREERTOS_ERRNO_EINVAL */
+ }
+
+ if( *( ( BaseType_t * ) pvOptionValue ) != 0 )
+ {
+ pxSocket->u.xTCP.bits.bRxStopped = pdTRUE_UNSIGNED;
+ }
+ else
+ {
+ pxSocket->u.xTCP.bits.bRxStopped = pdFALSE_UNSIGNED;
+ }
+
+ pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
+ pxSocket->u.xTCP.usTimeout = 1u; /* to set/clear bRxStopped */
+ xSendEventToIPTask( eTCPTimerEvent );
+ }
+ xReturn = 0;
+ break;
+
+ #endif /* ipconfigUSE_TCP == 1 */
+
+ default :
+ /* No other options are handled. */
+ xReturn = -pdFREERTOS_ERRNO_ENOPROTOOPT;
+ break;
+ }
+
+ return xReturn;
+} /* Tested */
+
+/*-----------------------------------------------------------*/
+
+/* Get a free private ('anonymous') port number */
+static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol )
+{
+uint16_t usResult;
+BaseType_t xIndex;
+const List_t *pxList;
+
+#if ipconfigUSE_TCP == 1
+ if( xProtocol == ( BaseType_t ) FREERTOS_IPPROTO_TCP )
+ {
+ xIndex = socketNEXT_TCP_PORT_NUMBER_INDEX;
+ pxList = &xBoundTCPSocketsList;
+ }
+ else
+#endif
+ {
+ xIndex = socketNEXT_UDP_PORT_NUMBER_INDEX;
+ pxList = &xBoundUDPSocketsList;
+ }
+
+ /* Avoid compiler warnings if ipconfigUSE_TCP is not defined. */
+ ( void ) xProtocol;
+
+ /* Assign the next port in the range. Has it overflowed? */
+ /*_RB_ This needs to be randomised rather than sequential. */
+ /* _HT_ Agreed, although many OS's use sequential port numbers, see
+ https://www.cymru.com/jtk/misc/ephemeralports.html */
+ for ( ;; )
+ {
+ ++( usNextPortToUse[ xIndex ] );
+
+ if( usNextPortToUse[ xIndex ] >= socketAUTO_PORT_ALLOCATION_MAX_NUMBER )
+ {
+ /* Don't go right back to the start of the dynamic/private port
+ range numbers as any persistent sockets are likely to have been
+ create first so the early port numbers may still be in use. */
+ usNextPortToUse[ xIndex ] = socketAUTO_PORT_ALLOCATION_RESET_NUMBER;
+ }
+
+ usResult = FreeRTOS_htons( usNextPortToUse[ xIndex ] );
+
+ if( pxListFindListItemWithValue( pxList, ( TickType_t ) usResult ) == NULL )
+ {
+ break;
+ }
+ }
+ return usResult;
+} /* Tested */
+/*-----------------------------------------------------------*/
+
+/* pxListFindListItemWithValue: find a list item in a bound socket list
+'xWantedItemValue' refers to a port number */
+static const ListItem_t * pxListFindListItemWithValue( const List_t *pxList, TickType_t xWantedItemValue )
+{
+const ListItem_t * pxResult = NULL;
+
+ if( ( xIPIsNetworkTaskReady() != pdFALSE ) && ( pxList != NULL ) )
+ {
+ const ListItem_t *pxIterator;
+ const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( pxList );
+ for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
+ pxIterator != ( const ListItem_t * ) pxEnd;
+ pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
+ {
+ if( listGET_LIST_ITEM_VALUE( pxIterator ) == xWantedItemValue )
+ {
+ pxResult = pxIterator;
+ break;
+ }
+ }
+ }
+
+ return pxResult;
+} /* Tested */
+
+/*-----------------------------------------------------------*/
+
+FreeRTOS_Socket_t *pxUDPSocketLookup( UBaseType_t uxLocalPort )
+{
+const ListItem_t *pxListItem;
+FreeRTOS_Socket_t *pxSocket = NULL;
+
+ /* Looking up a socket is quite simple, find a match with the local port.
+
+ See if there is a list item associated with the port number on the
+ list of bound sockets. */
+ pxListItem = pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) uxLocalPort );
+
+ if( pxListItem != NULL )
+ {
+ /* The owner of the list item is the socket itself. */
+ pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem );
+ configASSERT( pxSocket != NULL );
+ }
+ return pxSocket;
+}
+
+/*-----------------------------------------------------------*/
+
+#if ipconfigINCLUDE_FULL_INET_ADDR == 1
+
+ uint32_t FreeRTOS_inet_addr( const char * pcIPAddress )
+ {
+ const uint32_t ulDecimalBase = 10u;
+ uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
+ const char *pcPointerOnEntering;
+ uint32_t ulReturn = 0UL, ulValue;
+ UBaseType_t uxOctetNumber;
+ BaseType_t xResult = pdPASS;
+
+ for( uxOctetNumber = 0u; uxOctetNumber < socketMAX_IP_ADDRESS_OCTETS; uxOctetNumber++ )
+ {
+ ulValue = 0ul;
+ pcPointerOnEntering = pcIPAddress;
+
+ while( ( *pcIPAddress >= '0' ) && ( *pcIPAddress <= '9' ) )
+ {
+ /* Move previous read characters into the next decimal
+ position. */
+ ulValue *= ulDecimalBase;
+
+ /* Add the binary value of the ascii character. */
+ ulValue += ( ( uint32_t ) ( *pcIPAddress ) - ( uint32_t ) '0' );
+
+ /* Move to next character in the string. */
+ pcIPAddress++;
+ }
+
+ /* Check characters were read. */
+ if( pcIPAddress == pcPointerOnEntering )
+ {
+ xResult = pdFAIL;
+ }
+
+ /* Check the value fits in an 8-bit number. */
+ if( ulValue > 0xffUL )
+ {
+ xResult = pdFAIL;
+ }
+ else
+ {
+ ucOctet[ uxOctetNumber ] = ( uint8_t ) ulValue;
+
+ /* Check the next character is as expected. */
+ if( uxOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1u ) )
+ {
+ if( *pcIPAddress != '.' )
+ {
+ xResult = pdFAIL;
+ }
+ else
+ {
+ /* Move past the dot. */
+ pcIPAddress++;
+ }
+ }
+ }
+
+ if( xResult == pdFAIL )
+ {
+ /* No point going on. */
+ break;
+ }
+ }
+
+ if( *pcIPAddress != ( char ) 0 )
+ {
+ /* Expected the end of the string. */
+ xResult = pdFAIL;
+ }
+
+ if( uxOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
+ {
+ /* Didn't read enough octets. */
+ xResult = pdFAIL;
+ }
+
+ if( xResult == pdPASS )
+ {
+ ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
+ }
+
+ return ulReturn;
+ }
+
+#endif /* ipconfigINCLUDE_FULL_INET_ADDR */
+
+/*-----------------------------------------------------------*/
+
+/* Function to get the local address and IP port */
+size_t FreeRTOS_GetLocalAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress )
+{
+FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+
+ /* IP address of local machine. */
+ pxAddress->sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
+
+ /* Local port on this machine. */
+ pxAddress->sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
+
+ return sizeof( *pxAddress );
+}
+
+/*-----------------------------------------------------------*/
+
+void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket )
+{
+/* _HT_ must work this out, now vSocketWakeUpUser will be called for any important
+ * event or transition */
+ #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
+ {
+ if( pxSocket->pxUserSemaphore != NULL )
+ {
+ xSemaphoreGive( pxSocket->pxUserSemaphore );
+ }
+ }
+ #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
+
+ #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+ {
+ if( pxSocket->pxSocketSet != NULL )
+ {
+ EventBits_t xSelectBits = ( pxSocket->xEventBits >> SOCKET_EVENT_BIT_COUNT ) & eSELECT_ALL;
+ if( xSelectBits != 0ul )
+ {
+ pxSocket->xSocketBits |= xSelectBits;
+ xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, xSelectBits );
+ }
+ }
+
+ pxSocket->xEventBits &= eSOCKET_ALL;
+ }
+ #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
+
+ if( ( pxSocket->xEventGroup != NULL ) && ( pxSocket->xEventBits != 0u ) )
+ {
+ xEventGroupSetBits( pxSocket->xEventGroup, pxSocket->xEventBits );
+ }
+
+ pxSocket->xEventBits = 0ul;
+}
+
+/*-----------------------------------------------------------*/
+
+#if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
+
+ /* This define makes it possible for network-card drivers to inspect
+ * UDP message and see if there is any UDP socket bound to a given port
+ * number.
+ * This is probably only useful in systems with a minimum of RAM and
+ * when lots of anonymous broadcast messages come in
+ */
+ BaseType_t xPortHasUDPSocket( uint16_t usPortNr )
+ {
+ BaseType_t xFound = pdFALSE;
+
+ vTaskSuspendAll();
+ {
+ if( ( pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) usPortNr ) != NULL ) )
+ {
+ xFound = pdTRUE;
+ }
+ }
+ xTaskResumeAll();
+
+ return xFound;
+ }
+
+#endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
+
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ static BaseType_t bMayConnect( FreeRTOS_Socket_t *pxSocket );
+ static BaseType_t bMayConnect( FreeRTOS_Socket_t *pxSocket )
+ {
+ switch( pxSocket->u.xTCP.ucTCPState )
+ {
+ case eCLOSED:
+ case eCLOSE_WAIT: return 0;
+ case eCONNECT_SYN: return -pdFREERTOS_ERRNO_EINPROGRESS;
+ default: return -pdFREERTOS_ERRNO_EAGAIN;
+ }
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr *pxAddress )
+ {
+ BaseType_t xResult = 0;
+
+ if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdFALSE )
+ {
+ /* Not a valid socket or wrong type */
+ xResult = -pdFREERTOS_ERRNO_EBADF;
+ }
+ else if( FreeRTOS_issocketconnected( pxSocket ) > 0 )
+ {
+ /* The socket is already connected. */
+ xResult = -pdFREERTOS_ERRNO_EISCONN;
+ }
+ else if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
+ {
+ /* Bind the socket to the port that the client task will send from.
+ Non-standard, so the error returned is that returned by bind(). */
+ xResult = FreeRTOS_bind( ( Socket_t ) pxSocket, NULL, 0u );
+ }
+
+ if( xResult == 0 )
+ {
+ /* Check if it makes any sense to wait for a connect event, this condition
+ might change while sleeping, so it must be checked within each loop */
+ xResult = bMayConnect( pxSocket ); /* -EINPROGRESS, -EAGAIN, or 0 for OK */
+
+ /* Start the connect procedure, kernel will start working on it */
+ if( xResult == 0 )
+ {
+ pxSocket->u.xTCP.bits.bConnPrepared = pdFALSE_UNSIGNED;
+ pxSocket->u.xTCP.ucRepCount = 0u;
+
+ FreeRTOS_debug_printf( ( "FreeRTOS_connect: %u to %lxip:%u\n",
+ pxSocket->usLocalPort, FreeRTOS_ntohl( pxAddress->sin_addr ), FreeRTOS_ntohs( pxAddress->sin_port ) ) );
+
+ /* Port on remote machine. */
+ pxSocket->u.xTCP.usRemotePort = FreeRTOS_ntohs( pxAddress->sin_port );
+
+ /* IP address of remote machine. */
+ pxSocket->u.xTCP.ulRemoteIP = FreeRTOS_ntohl( pxAddress->sin_addr );
+
+ /* (client) internal state: socket wants to send a connect. */
+ vTCPStateChange( pxSocket, eCONNECT_SYN );
+
+ /* To start an active connect. */
+ pxSocket->u.xTCP.usTimeout = 1u;
+
+ if( xSendEventToIPTask( eTCPTimerEvent ) != pdPASS )
+ {
+ xResult = -pdFREERTOS_ERRNO_ECANCELED;
+ }
+ }
+ }
+
+ return xResult;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /*
+ * FreeRTOS_connect: socket wants to connect to a remote port
+ */
+ BaseType_t FreeRTOS_connect( Socket_t xClientSocket, struct freertos_sockaddr *pxAddress, socklen_t xAddressLength )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t* ) xClientSocket;
+ TickType_t xRemainingTime;
+ BaseType_t xTimed = pdFALSE;
+ BaseType_t xResult;
+ TimeOut_t xTimeOut;
+
+ ( void ) xAddressLength;
+
+ xResult = prvTCPConnectStart( pxSocket, pxAddress );
+
+ if( xResult == 0 )
+ {
+ /* And wait for the result */
+ for( ;; )
+ {
+ if( xTimed == pdFALSE )
+ {
+ /* Only in the first round, check for non-blocking */
+ xRemainingTime = pxSocket->xReceiveBlockTime;
+ if( xRemainingTime == ( TickType_t )0 )
+ {
+ /* Not yet connected, correct state, non-blocking. */
+ xResult = -pdFREERTOS_ERRNO_EWOULDBLOCK;
+ break;
+ }
+
+ /* Don't get here a second time. */
+ xTimed = pdTRUE;
+
+ /* Fetch the current time */
+ vTaskSetTimeOutState( &xTimeOut );
+ }
+
+ /* Did it get connected while sleeping ? */
+ xResult = FreeRTOS_issocketconnected( pxSocket );
+
+ /* Returns positive when connected, negative means an error */
+ if( xResult < 0 )
+ {
+ /* Return the error */
+ break;
+ }
+
+ if( xResult > 0 )
+ {
+ /* Socket now connected, return a zero */
+ xResult = 0;
+ break;
+ }
+
+ /* Is it allowed to sleep more? */
+ if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) )
+ {
+ xResult = -pdFREERTOS_ERRNO_ETIMEDOUT;
+ break;
+ }
+
+ /* Go sleeping until we get any down-stream event */
+ xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_CONNECT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
+ }
+ }
+
+ return xResult;
+ }
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /*
+ * FreeRTOS_accept: can return a new connected socket
+ * if the server socket is in listen mode and receives a connection request
+ * The new socket will be bound already to the same port number as the listing
+ * socket.
+ */
+ Socket_t FreeRTOS_accept( Socket_t xServerSocket, struct freertos_sockaddr *pxAddress, socklen_t *pxAddressLength )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xServerSocket;
+ FreeRTOS_Socket_t *pxClientSocket = NULL;
+ TickType_t xRemainingTime;
+ BaseType_t xTimed = pdFALSE, xAsk = pdFALSE;
+ TimeOut_t xTimeOut;
+ IPStackEvent_t xAskEvent;
+
+ if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
+ {
+ /* Not a valid socket or wrong type */
+ pxClientSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
+ }
+ else if( ( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) &&
+ ( pxSocket->u.xTCP.ucTCPState != eTCP_LISTEN ) )
+ {
+ /* Parent socket is not in listening mode */
+ pxClientSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
+ }
+ else
+ {
+ /* Loop will stop with breaks. */
+ for( ; ; )
+ {
+ /* Is there a new client? */
+ vTaskSuspendAll();
+ {
+ if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
+ {
+ pxClientSocket = pxSocket->u.xTCP.pxPeerSocket;
+ }
+ else
+ {
+ pxClientSocket = pxSocket;
+ }
+ if( pxClientSocket != NULL )
+ {
+ pxSocket->u.xTCP.pxPeerSocket = NULL;
+
+ /* Is it still not taken ? */
+ if( pxClientSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED )
+ {
+ pxClientSocket->u.xTCP.bits.bPassAccept = pdFALSE_UNSIGNED;
+ }
+ else
+ {
+ pxClientSocket = NULL;
+ }
+ }
+ }
+ xTaskResumeAll();
+
+ if( pxClientSocket != NULL )
+ {
+ if( pxAddress != NULL )
+ {
+ /* IP address of remote machine. */
+ pxAddress->sin_addr = FreeRTOS_ntohl( pxClientSocket->u.xTCP.ulRemoteIP );
+
+ /* Port on remote machine. */
+ pxAddress->sin_port = FreeRTOS_ntohs( pxClientSocket->u.xTCP.usRemotePort );
+ }
+ if( pxAddressLength != NULL )
+ {
+ *pxAddressLength = sizeof( *pxAddress );
+ }
+
+ if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
+ {
+ xAsk = pdTRUE;
+ }
+ }
+
+ if( xAsk != pdFALSE )
+ {
+ /* Ask to set an event in 'xEventGroup' as soon as a new
+ client gets connected for this listening socket. */
+ xAskEvent.eEventType = eTCPAcceptEvent;
+ xAskEvent.pvData = ( void * ) pxSocket;
+ xSendEventStructToIPTask( &xAskEvent, portMAX_DELAY );
+ }
+
+ if( pxClientSocket != NULL )
+ {
+ break;
+ }
+
+ if( xTimed == pdFALSE )
+ {
+ /* Only in the first round, check for non-blocking */
+ xRemainingTime = pxSocket->xReceiveBlockTime;
+ if( xRemainingTime == ( TickType_t ) 0 )
+ {
+ break;
+ }
+
+ /* Don't get here a second time */
+ xTimed = pdTRUE;
+
+ /* Fetch the current time */
+ vTaskSetTimeOutState( &xTimeOut );
+ }
+
+ /* Has the timeout been reached? */
+ if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
+ {
+ break;
+ }
+
+ /* Go sleeping until we get any down-stream event */
+ xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_ACCEPT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
+ }
+ }
+
+ return ( Socket_t ) pxClientSocket;
+ }
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /*
+ * Read incoming data from a TCP socket
+ * Only after the last byte has been read, a close error might be returned
+ */
+ BaseType_t FreeRTOS_recv( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags )
+ {
+ BaseType_t xByteCount;
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ TickType_t xRemainingTime;
+ BaseType_t xTimed = pdFALSE;
+ TimeOut_t xTimeOut;
+ EventBits_t xEventBits = ( EventBits_t ) 0;
+
+ /* Check if the socket is valid, has type TCP and if it is bound to a
+ port. */
+ if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
+ {
+ xByteCount = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else
+ {
+ if( pxSocket->u.xTCP.rxStream != NULL )
+ {
+ xByteCount = ( BaseType_t )uxStreamBufferGetSize ( pxSocket->u.xTCP.rxStream );
+ }
+ else
+ {
+ xByteCount = 0;
+ }
+
+ while( xByteCount == 0 )
+ {
+ switch( pxSocket->u.xTCP.ucTCPState )
+ {
+ case eCLOSED:
+ case eCLOSE_WAIT: /* (server + client) waiting for a connection termination request from the local user. */
+ case eCLOSING: /* (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */
+ if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED )
+ {
+ /* The no-memory error has priority above the non-connected error.
+ Both are fatal and will elad to closing the socket. */
+ xByteCount = -pdFREERTOS_ERRNO_ENOMEM;
+ }
+ else
+ {
+ xByteCount = -pdFREERTOS_ERRNO_ENOTCONN;
+ }
+ /* Call continue to break out of the switch and also the while
+ loop. */
+ continue;
+ default:
+ break;
+ }
+
+ if( xTimed == pdFALSE )
+ {
+ /* Only in the first round, check for non-blocking. */
+ xRemainingTime = pxSocket->xReceiveBlockTime;
+
+ if( xRemainingTime == ( TickType_t ) 0 )
+ {
+ #if( ipconfigSUPPORT_SIGNALS != 0 )
+ {
+ /* Just check for the interrupt flag. */
+ xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_INTR,
+ pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
+ }
+ #endif /* ipconfigSUPPORT_SIGNALS */
+ break;
+ }
+
+ if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 )
+ {
+ break;
+ }
+
+ /* Don't get here a second time. */
+ xTimed = pdTRUE;
+
+ /* Fetch the current time. */
+ vTaskSetTimeOutState( &xTimeOut );
+ }
+
+ /* Has the timeout been reached? */
+ if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
+ {
+ break;
+ }
+
+ /* Block until there is a down-stream event. */
+ xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup,
+ eSOCKET_RECEIVE | eSOCKET_CLOSED | eSOCKET_INTR,
+ pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
+ #if( ipconfigSUPPORT_SIGNALS != 0 )
+ {
+ if( ( xEventBits & eSOCKET_INTR ) != 0u )
+ {
+ break;
+ }
+ }
+ #else
+ {
+ ( void ) xEventBits;
+ }
+ #endif /* ipconfigSUPPORT_SIGNALS */
+
+ if( pxSocket->u.xTCP.rxStream != NULL )
+ {
+ xByteCount = ( BaseType_t ) uxStreamBufferGetSize ( pxSocket->u.xTCP.rxStream );
+ }
+ else
+ {
+ xByteCount = 0;
+ }
+ }
+
+ #if( ipconfigSUPPORT_SIGNALS != 0 )
+ if( ( xEventBits & eSOCKET_INTR ) != 0 )
+ {
+ if( ( xEventBits & ( eSOCKET_RECEIVE | eSOCKET_CLOSED ) ) != 0 )
+ {
+ /* Shouldn't have cleared other flags. */
+ xEventBits &= ~eSOCKET_INTR;
+ xEventGroupSetBits( pxSocket->xEventGroup, xEventBits );
+ }
+ xByteCount = -pdFREERTOS_ERRNO_EINTR;
+ }
+ else
+ #endif /* ipconfigSUPPORT_SIGNALS */
+ if( xByteCount > 0 )
+ {
+ if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 )
+ {
+ xByteCount = ( BaseType_t ) uxStreamBufferGet( pxSocket->u.xTCP.rxStream, 0ul, ( uint8_t * ) pvBuffer, ( size_t ) xBufferLength, ( xFlags & FREERTOS_MSG_PEEK ) != 0 );
+ if( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED )
+ {
+ /* We had reached the low-water mark, now see if the flag
+ can be cleared */
+ size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
+
+ if( uxFrontSpace >= pxSocket->u.xTCP.uxEnoughSpace )
+ {
+ pxSocket->u.xTCP.bits.bLowWater = pdFALSE_UNSIGNED;
+ pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
+ pxSocket->u.xTCP.usTimeout = 1u; /* because bLowWater is cleared. */
+ xSendEventToIPTask( eTCPTimerEvent );
+ }
+ }
+ }
+ else
+ {
+ /* Zero-copy reception of data: pvBuffer is a pointer to a pointer. */
+ xByteCount = ( BaseType_t ) uxStreamBufferGetPtr( pxSocket->u.xTCP.rxStream, (uint8_t **)pvBuffer );
+ }
+ }
+ } /* prvValidSocket() */
+
+ return xByteCount;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ static int32_t prvTCPSendCheck( FreeRTOS_Socket_t *pxSocket, size_t xDataLength )
+ {
+ int32_t xResult = 1;
+
+ /* Is this a socket of type TCP and is it already bound to a port number ? */
+ if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
+ {
+ xResult = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED )
+ {
+ xResult = -pdFREERTOS_ERRNO_ENOMEM;
+ }
+ else if( pxSocket->u.xTCP.ucTCPState == eCLOSED )
+ {
+ xResult = -pdFREERTOS_ERRNO_ENOTCONN;
+ }
+ else if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
+ {
+ /* This TCP connection is closing already, the FIN flag has been sent.
+ Maybe it is still delivering or receiving data.
+ Return OK in order not to get closed/deleted too quickly */
+ xResult = 0;
+ }
+ else if( xDataLength == 0ul )
+ {
+ /* send() is being called to send zero bytes */
+ xResult = 0;
+ }
+ else if( pxSocket->u.xTCP.txStream == NULL )
+ {
+ /* Create the outgoing stream only when it is needed */
+ prvTCPCreateStream( pxSocket, pdFALSE );
+
+ if( pxSocket->u.xTCP.txStream == NULL )
+ {
+ xResult = -pdFREERTOS_ERRNO_ENOMEM;
+ }
+ }
+
+ return xResult;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /* Get a direct pointer to the circular transmit buffer.
+ '*pxLength' will contain the number of bytes that may be written. */
+ uint8_t *FreeRTOS_get_tx_head( Socket_t xSocket, BaseType_t *pxLength )
+ {
+ uint8_t *pucReturn;
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ StreamBuffer_t *pxBuffer = pxSocket->u.xTCP.txStream;
+
+ if( pxBuffer != NULL )
+ {
+ BaseType_t xSpace = ( BaseType_t ) uxStreamBufferGetSpace( pxBuffer );
+ BaseType_t xRemain = ( BaseType_t ) ( pxBuffer->LENGTH - pxBuffer->uxHead );
+
+ *pxLength = FreeRTOS_min_BaseType( xSpace, xRemain );
+ pucReturn = pxBuffer->ucArray + pxBuffer->uxHead;
+ }
+ else
+ {
+ *pxLength = 0;
+ pucReturn = NULL;
+ }
+
+ return pucReturn;
+ }
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+ /*
+ * Send data using a TCP socket. It is not necessary to have the socket
+ * connected already. Outgoing data will be stored and delivered as soon as
+ * the socket gets connected.
+ */
+ BaseType_t FreeRTOS_send( Socket_t xSocket, const void *pvBuffer, size_t uxDataLength, BaseType_t xFlags )
+ {
+ BaseType_t xByteCount;
+ BaseType_t xBytesLeft;
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ TickType_t xRemainingTime;
+ BaseType_t xTimed = pdFALSE;
+ TimeOut_t xTimeOut;
+ BaseType_t xCloseAfterSend;
+
+ /* Prevent compiler warnings about unused parameters. The parameter
+ may be used in future versions. */
+ ( void ) xFlags;
+
+ xByteCount = ( BaseType_t ) prvTCPSendCheck( pxSocket, uxDataLength );
+
+ if( xByteCount > 0 )
+ {
+ /* xBytesLeft is number of bytes to send, will count to zero. */
+ xBytesLeft = ( BaseType_t ) uxDataLength;
+
+ /* xByteCount is number of bytes that can be sent now. */
+ xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
+
+ /* While there are still bytes to be sent. */
+ while( xBytesLeft > 0 )
+ {
+ /* If txStream has space. */
+ if( xByteCount > 0 )
+ {
+ /* Don't send more than necessary. */
+ if( xByteCount > xBytesLeft )
+ {
+ xByteCount = xBytesLeft;
+ }
+
+ /* Is the close-after-send flag set and is this really the
+ last transmission? */
+ if( ( pxSocket->u.xTCP.bits.bCloseAfterSend != pdFALSE_UNSIGNED ) && ( xByteCount == xBytesLeft ) )
+ {
+ xCloseAfterSend = pdTRUE;
+ }
+ else
+ {
+ xCloseAfterSend = pdFALSE;
+ }
+
+ /* The flag 'bCloseAfterSend' can be set before sending data
+ using setsockopt()
+
+ When the last data packet is being sent out, a FIN flag will
+ be included to let the peer know that no more data is to be
+ expected. The use of 'bCloseAfterSend' is not mandatory, it
+ is just a faster way of transferring files (e.g. when using
+ FTP). */
+ if( xCloseAfterSend != pdFALSE )
+ {
+ /* Now suspend the scheduler: sending the last data and
+ setting bCloseRequested must be done together */
+ vTaskSuspendAll();
+ pxSocket->u.xTCP.bits.bCloseRequested = pdTRUE_UNSIGNED;
+ }
+
+ xByteCount = ( BaseType_t ) uxStreamBufferAdd( pxSocket->u.xTCP.txStream, 0ul, ( const uint8_t * ) pvBuffer, ( size_t ) xByteCount );
+
+ if( xCloseAfterSend != pdFALSE )
+ {
+ /* Now when the IP-task transmits the data, it will also
+ see that bCloseRequested is true and include the FIN
+ flag to start closure of the connection. */
+ xTaskResumeAll();
+ }
+
+ /* Send a message to the IP-task so it can work on this
+ socket. Data is sent, let the IP-task work on it. */
+ pxSocket->u.xTCP.usTimeout = 1u;
+
+ if( xIsCallingFromIPTask() == pdFALSE )
+ {
+ /* Only send a TCP timer event when not called from the
+ IP-task. */
+ xSendEventToIPTask( eTCPTimerEvent );
+ }
+
+ xBytesLeft -= xByteCount;
+
+ if( xBytesLeft == 0 )
+ {
+ break;
+ }
+
+ /* As there are still bytes left to be sent, increase the
+ data pointer. */
+ pvBuffer = ( void * ) ( ( ( const uint8_t * ) pvBuffer) + xByteCount );
+ }
+
+ /* Not all bytes have been sent. In case the socket is marked as
+ blocking sleep for a while. */
+ if( xTimed == pdFALSE )
+ {
+ /* Only in the first round, check for non-blocking. */
+ xRemainingTime = pxSocket->xSendBlockTime;
+
+ #if( ipconfigUSE_CALLBACKS != 0 )
+ {
+ if( xIsCallingFromIPTask() != pdFALSE )
+ {
+ /* If this send function is called from within a
+ call-back handler it may not block, otherwise
+ chances would be big to get a deadlock: the IP-task
+ waiting for itself. */
+ xRemainingTime = ( TickType_t ) 0;
+ }
+ }
+ #endif /* ipconfigUSE_CALLBACKS */
+
+ if( xRemainingTime == ( TickType_t ) 0 )
+ {
+ break;
+ }
+
+ if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 )
+ {
+ break;
+ }
+
+ /* Don't get here a second time. */
+ xTimed = pdTRUE;
+
+ /* Fetch the current time. */
+ vTaskSetTimeOutState( &xTimeOut );
+ }
+ else
+ {
+ /* Has the timeout been reached? */
+ if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
+ {
+ break;
+ }
+ }
+
+ /* Go sleeping until down-stream events are received. */
+ xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_SEND | eSOCKET_CLOSED,
+ pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
+
+ xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
+ }
+
+ /* How much was actually sent? */
+ xByteCount = ( ( BaseType_t ) uxDataLength ) - xBytesLeft;
+
+ if( xByteCount == 0 )
+ {
+ if( pxSocket->u.xTCP.ucTCPState > eESTABLISHED )
+ {
+ xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOTCONN;
+ }
+ else
+ {
+ if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )
+ {
+ FreeRTOS_debug_printf( ( "FreeRTOS_send: %u -> %lxip:%d: no space\n",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.ulRemoteIP,
+ pxSocket->u.xTCP.usRemotePort ) );
+ }
+
+ xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOSPC;
+ }
+ }
+ }
+
+ return xByteCount;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /*
+ * Request to put a socket in listen mode
+ */
+ BaseType_t FreeRTOS_listen( Socket_t xSocket, BaseType_t xBacklog )
+ {
+ FreeRTOS_Socket_t *pxSocket;
+ BaseType_t xResult = 0;
+
+ pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+
+ /* listen() is allowed for a valid TCP socket in Closed state and already
+ bound. */
+ if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
+ {
+ xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
+ }
+ else if( ( pxSocket->u.xTCP.ucTCPState != eCLOSED ) && ( pxSocket->u.xTCP.ucTCPState != eCLOSE_WAIT ) )
+ {
+ /* Socket is in a wrong state. */
+ xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
+ }
+ else
+ {
+ /* Backlog is interpreted here as "the maximum number of child
+ sockets. */
+ pxSocket->u.xTCP.usBacklog = ( uint16_t )FreeRTOS_min_int32( ( int32_t ) 0xffff, ( int32_t ) xBacklog );
+
+ /* This cleaning is necessary only if a listening socket is being
+ reused as it might have had a previous connection. */
+ if( pxSocket->u.xTCP.bits.bReuseSocket )
+ {
+ if( pxSocket->u.xTCP.rxStream != NULL )
+ {
+ vStreamBufferClear( pxSocket->u.xTCP.rxStream );
+ }
+
+ if( pxSocket->u.xTCP.txStream != NULL )
+ {
+ vStreamBufferClear( pxSocket->u.xTCP.txStream );
+ }
+
+ memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
+ memset( &pxSocket->u.xTCP.xTCPWindow, '\0', sizeof( pxSocket->u.xTCP.xTCPWindow ) );
+ memset( &pxSocket->u.xTCP.bits, '\0', sizeof( pxSocket->u.xTCP.bits ) );
+
+ /* Now set the bReuseSocket flag again, because the bits have
+ just been cleared. */
+ pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED;
+ }
+
+ vTCPStateChange( pxSocket, eTCP_LISTEN );
+ }
+
+ return xResult;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /* shutdown - shut down part of a full-duplex connection */
+ BaseType_t FreeRTOS_shutdown( Socket_t xSocket, BaseType_t xHow )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ BaseType_t xResult;
+
+ if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
+ {
+ /*_RB_ Is this comment correct? The socket is not of a type that
+ supports the listen() operation. */
+ xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
+ }
+ else if ( pxSocket->u.xTCP.ucTCPState != eESTABLISHED )
+ {
+ /*_RB_ Is this comment correct? The socket is not of a type that
+ supports the listen() operation. */
+ xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
+ }
+ else
+ {
+ pxSocket->u.xTCP.bits.bUserShutdown = pdTRUE_UNSIGNED;
+
+ /* Let the IP-task perform the shutdown of the connection. */
+ pxSocket->u.xTCP.usTimeout = 1u;
+ xSendEventToIPTask( eTCPTimerEvent );
+ xResult = 0;
+ }
+ (void) xHow;
+
+ return xResult;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /*
+ * A TCP timer has expired, now check all TCP sockets for:
+ * - Active connect
+ * - Send a delayed ACK
+ * - Send new data
+ * - Send a keep-alive packet
+ * - Check for timeout (in non-connected states only)
+ */
+ TickType_t xTCPTimerCheck( BaseType_t xWillSleep )
+ {
+ FreeRTOS_Socket_t *pxSocket;
+ TickType_t xShortest = pdMS_TO_TICKS( ( TickType_t ) ipTCP_TIMER_PERIOD_MS );
+ TickType_t xNow = xTaskGetTickCount();
+ static TickType_t xLastTime = 0u;
+ TickType_t xDelta = xNow - xLastTime;
+ ListItem_t* pxEnd = ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
+ ListItem_t *pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
+
+ xLastTime = xNow;
+
+ if( xDelta == 0u )
+ {
+ xDelta = 1u;
+ }
+
+ while( pxIterator != pxEnd )
+ {
+ pxSocket = ( FreeRTOS_Socket_t * )listGET_LIST_ITEM_OWNER( pxIterator );
+ pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator );
+
+ /* Sockets with 'tmout == 0' do not need any regular attention. */
+ if( pxSocket->u.xTCP.usTimeout == 0u )
+ {
+ continue;
+ }
+
+ if( xDelta < ( TickType_t ) pxSocket->u.xTCP.usTimeout )
+ {
+ pxSocket->u.xTCP.usTimeout = ( uint16_t ) ( ( ( TickType_t ) pxSocket->u.xTCP.usTimeout ) - xDelta );
+ }
+ else
+ {
+ int rc ;
+ pxSocket->u.xTCP.usTimeout = 0u;
+ rc = xTCPSocketCheck( pxSocket );
+
+ /* Within this function, the socket might want to send a delayed
+ ack or send out data or whatever it needs to do. */
+ if( rc < 0 )
+ {
+ /* Continue because the socket was deleted. */
+ continue;
+ }
+ }
+
+ /* In xEventBits the driver may indicate that the socket has
+ important events for the user. These are only done just before the
+ IP-task goes to sleep. */
+ if( pxSocket->xEventBits != 0u )
+ {
+ if( xWillSleep != pdFALSE )
+ {
+ /* The IP-task is about to go to sleep, so messages can be
+ sent to the socket owners. */
+ vSocketWakeUpUser( pxSocket );
+ }
+ else
+ {
+ /* Or else make sure this will be called again to wake-up
+ the sockets' owner. */
+ xShortest = ( TickType_t ) 0;
+ }
+ }
+
+ if( ( pxSocket->u.xTCP.usTimeout != 0u ) && ( xShortest > ( TickType_t ) pxSocket->u.xTCP.usTimeout ) )
+ {
+ xShortest = ( TickType_t ) pxSocket->u.xTCP.usTimeout;
+ }
+ }
+
+ return xShortest;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /*
+ * TCP: as multiple sockets may be bound to the same local port number
+ * looking up a socket is a little more complex:
+ * Both a local port, and a remote port and IP address are being used
+ * For a socket in listening mode, the remote port and IP address are both 0
+ */
+ FreeRTOS_Socket_t *pxTCPSocketLookup( uint32_t ulLocalIP, UBaseType_t uxLocalPort, uint32_t ulRemoteIP, UBaseType_t uxRemotePort )
+ {
+ ListItem_t *pxIterator;
+ FreeRTOS_Socket_t *pxResult = NULL, *pxListenSocket = NULL;
+ MiniListItem_t *pxEnd = ( MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList );
+
+ /* Parameter not yet supported. */
+ ( void ) ulLocalIP;
+
+ for( pxIterator = ( ListItem_t * ) listGET_NEXT( pxEnd );
+ pxIterator != ( ListItem_t * ) pxEnd;
+ pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+
+ if( pxSocket->usLocalPort == ( uint16_t ) uxLocalPort )
+ {
+ if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
+ {
+ /* If this is a socket listening to uxLocalPort, remember it
+ in case there is no perfect match. */
+ pxListenSocket = pxSocket;
+ }
+ else if( ( pxSocket->u.xTCP.usRemotePort == ( uint16_t ) uxRemotePort ) && ( pxSocket->u.xTCP.ulRemoteIP == ulRemoteIP ) )
+ {
+ /* For sockets not in listening mode, find a match with
+ xLocalPort, ulRemoteIP AND xRemotePort. */
+ pxResult = pxSocket;
+ break;
+ }
+ }
+ }
+ if( pxResult == NULL )
+ {
+ /* An exact match was not found, maybe a listening socket was
+ found. */
+ pxResult = pxListenSocket;
+ }
+
+ return pxResult;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ const struct xSTREAM_BUFFER *FreeRTOS_get_rx_buf( Socket_t xSocket )
+ {
+ FreeRTOS_Socket_t *pxSocket = (FreeRTOS_Socket_t *)xSocket;
+
+ return pxSocket->u.xTCP.rxStream;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ static StreamBuffer_t *prvTCPCreateStream ( FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream )
+ {
+ StreamBuffer_t *pxBuffer;
+ size_t uxLength;
+ size_t uxSize;
+
+ /* Now that a stream is created, the maximum size is fixed before
+ creation, it could still be changed with setsockopt(). */
+ if( xIsInputStream != pdFALSE )
+ {
+ uxLength = pxSocket->u.xTCP.uxRxStreamSize;
+
+ if( pxSocket->u.xTCP.uxLittleSpace == 0ul )
+ {
+ pxSocket->u.xTCP.uxLittleSpace = ( 1ul * pxSocket->u.xTCP.uxRxStreamSize ) / 5u; /*_RB_ Why divide by 5? Can this be changed to a #define? */
+ }
+
+ if( pxSocket->u.xTCP.uxEnoughSpace == 0ul )
+ {
+ pxSocket->u.xTCP.uxEnoughSpace = ( 4ul * pxSocket->u.xTCP.uxRxStreamSize ) / 5u; /*_RB_ Why multiply by 4? Maybe sock80_PERCENT?*/
+ }
+ }
+ else
+ {
+ uxLength = pxSocket->u.xTCP.uxTxStreamSize;
+ }
+
+ /* Add an extra 4 (or 8) bytes. */
+ uxLength += sizeof( size_t );
+
+ /* And make the length a multiple of sizeof( size_t ). */
+ uxLength &= ~( sizeof( size_t ) - 1u );
+
+ uxSize = sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) + uxLength;
+
+ pxBuffer = ( StreamBuffer_t * )pvPortMallocLarge( uxSize );
+
+ if( pxBuffer == NULL )
+ {
+ FreeRTOS_debug_printf( ( "prvTCPCreateStream: malloc failed\n" ) );
+ pxSocket->u.xTCP.bits.bMallocError = pdTRUE_UNSIGNED;
+ vTCPStateChange( pxSocket, eCLOSE_WAIT );
+ }
+ else
+ {
+ /* Clear the markers of the stream */
+ memset( pxBuffer, '\0', sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) );
+ pxBuffer->LENGTH = ( size_t ) uxLength ;
+
+ if( xTCPWindowLoggingLevel != 0 )
+ {
+ FreeRTOS_debug_printf( ( "prvTCPCreateStream: %cxStream created %lu bytes (total %lu)\n", xIsInputStream ? 'R' : 'T', uxLength, uxSize ) );
+ }
+
+ if( xIsInputStream != 0 )
+ {
+ pxSocket->u.xTCP.rxStream = pxBuffer;
+ }
+ else
+ {
+ pxSocket->u.xTCP.txStream = pxBuffer;
+ }
+ }
+
+ return pxBuffer;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /*
+ * Add data to the RxStream. When uxOffset > 0, data has come in out-of-order
+ * and will be put in front of the head so it can not be popped by the user.
+ */
+ int32_t lTCPAddRxdata( FreeRTOS_Socket_t *pxSocket, size_t uxOffset, const uint8_t *pcData, uint32_t ulByteCount )
+ {
+ StreamBuffer_t *pxStream = pxSocket->u.xTCP.rxStream;
+ int32_t xResult;
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ BaseType_t bHasHandler = ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleReceive );
+ const uint8_t *pucBuffer = NULL;
+ #endif /* ipconfigUSE_CALLBACKS */
+
+ /* int32_t uxStreamBufferAdd( pxBuffer, uxOffset, pucData, aCount )
+ if( pucData != NULL ) copy data the the buffer
+ if( pucData == NULL ) no copying, just advance rxHead
+ if( uxOffset != 0 ) Just store data which has come out-of-order
+ if( uxOffset == 0 ) Also advance rxHead */
+ if( pxStream == NULL )
+ {
+ pxStream = prvTCPCreateStream( pxSocket, pdTRUE );
+ if( pxStream == NULL )
+ {
+ return -1;
+ }
+ }
+
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ {
+ if( ( bHasHandler != pdFALSE ) && ( uxStreamBufferGetSize( pxStream ) == 0u ) && ( uxOffset == 0ul ) && ( pcData != NULL ) )
+ {
+ /* Data can be passed directly to the user */
+ pucBuffer = pcData;
+
+ /* Zero-copy for call-back: no need to add the bytes to the
+ stream, only the pointer will be advanced by uxStreamBufferAdd(). */
+ pcData = NULL;
+ }
+ }
+ #endif /* ipconfigUSE_CALLBACKS */
+
+ xResult = ( int32_t ) uxStreamBufferAdd( pxStream, uxOffset, pcData, ( size_t ) ulByteCount );
+
+ #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+ {
+ if( xResult != ( int32_t ) ulByteCount )
+ {
+ FreeRTOS_debug_printf( ( "lTCPAddRxdata: at %ld: %ld/%lu bytes (tail %lu head %lu space %lu front %lu)\n",
+ uxOffset, xResult, ulByteCount,
+ pxStream->uxTail,
+ pxStream->uxHead,
+ uxStreamBufferFrontSpace( pxStream ),
+ pxStream->uxFront ) );
+ }
+ }
+ #endif /* ipconfigHAS_DEBUG_PRINTF */
+
+ if( uxOffset == 0u )
+ {
+ /* Data is being added to rxStream at the head (offs = 0) */
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ if( bHasHandler != pdFALSE )
+ {
+ /* The socket owner has installed an OnReceive handler. Pass the
+ Rx data, without copying from the rxStream, to the user. */
+ for (;;)
+ {
+ uint8_t *ucReadPtr = NULL;
+ uint32_t ulCount;
+ if( pucBuffer != NULL )
+ {
+ ucReadPtr = ( uint8_t * )pucBuffer;
+ ulCount = ulByteCount;
+ pucBuffer = NULL;
+ }
+ else
+ {
+ ulCount = ( uint32_t ) uxStreamBufferGetPtr( pxStream, &( ucReadPtr ) );
+ }
+
+ if( ulCount == 0ul )
+ {
+ break;
+ }
+
+ if( pxSocket->u.xTCP.pxHandleReceive( (Socket_t *)pxSocket, ( void* )ucReadPtr, ( size_t ) ulCount ) != pdFALSE )
+ {
+ uxStreamBufferGet( pxStream, 0ul, NULL, ( size_t ) ulCount, pdFALSE );
+ }
+ }
+ } else
+ #endif /* ipconfigUSE_CALLBACKS */
+ {
+ /* See if running out of space. */
+ if( pxSocket->u.xTCP.bits.bLowWater == pdFALSE_UNSIGNED )
+ {
+ size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
+ if( uxFrontSpace <= pxSocket->u.xTCP.uxLittleSpace )
+ {
+ pxSocket->u.xTCP.bits.bLowWater = pdTRUE_UNSIGNED;
+ pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
+
+ /* bLowWater was reached, send the changed window size. */
+ pxSocket->u.xTCP.usTimeout = 1u;
+ xSendEventToIPTask( eTCPTimerEvent );
+ }
+ }
+
+ /* New incoming data is available, wake up the user. User's
+ semaphores will be set just before the IP-task goes asleep. */
+ pxSocket->xEventBits |= eSOCKET_RECEIVE;
+
+ #if ipconfigSUPPORT_SELECT_FUNCTION == 1
+ {
+ if( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 )
+ {
+ pxSocket->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );
+ }
+ }
+ #endif
+ }
+ }
+
+ return xResult;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /* Function to get the remote address and IP port */
+ BaseType_t FreeRTOS_GetRemoteAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ BaseType_t xResult;
+
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ xResult = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else
+ {
+ /* BSD style sockets communicate IP and port addresses in network
+ byte order.
+
+ IP address of remote machine. */
+ pxAddress->sin_addr = FreeRTOS_htonl ( pxSocket->u.xTCP.ulRemoteIP );
+
+ /* Port on remote machine. */
+ pxAddress->sin_port = FreeRTOS_htons ( pxSocket->u.xTCP.usRemotePort );
+
+ xResult = ( BaseType_t ) sizeof( ( *pxAddress ) );
+ }
+
+ return xResult;
+ }
+
+#endif /* ipconfigUSE_TCP */
+
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /* Returns the number of bytes that may be added to txStream */
+ BaseType_t FreeRTOS_maywrite( Socket_t xSocket )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ BaseType_t xResult;
+
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ xResult = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else if( pxSocket->u.xTCP.ucTCPState != eESTABLISHED )
+ {
+ if( ( pxSocket->u.xTCP.ucTCPState < eCONNECT_SYN ) || ( pxSocket->u.xTCP.ucTCPState > eESTABLISHED ) )
+ {
+ xResult = -1;
+ }
+ else
+ {
+ xResult = 0;
+ }
+ }
+ else if( pxSocket->u.xTCP.txStream == NULL )
+ {
+ xResult = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize;
+ }
+ else
+ {
+ xResult = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
+ }
+
+ return xResult;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP ==1 )
+
+ BaseType_t FreeRTOS_tx_space( Socket_t xSocket )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ BaseType_t xReturn;
+
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ xReturn = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else
+ {
+ if( pxSocket->u.xTCP.txStream != NULL )
+ {
+ xReturn = ( BaseType_t ) uxStreamBufferGetSpace ( pxSocket->u.xTCP.txStream );
+ }
+ else
+ {
+ xReturn = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize;
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ BaseType_t FreeRTOS_tx_size( Socket_t xSocket )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ BaseType_t xReturn;
+
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ xReturn = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else
+ {
+ if( pxSocket->u.xTCP.txStream != NULL )
+ {
+ xReturn = ( BaseType_t ) uxStreamBufferGetSize ( pxSocket->u.xTCP.txStream );
+ }
+ else
+ {
+ xReturn = 0;
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /* Returns pdTRUE if TCP socket is connected. */
+ BaseType_t FreeRTOS_issocketconnected( Socket_t xSocket )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ BaseType_t xReturn = pdFALSE;
+
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ xReturn = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else
+ {
+ if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )
+ {
+ if( pxSocket->u.xTCP.ucTCPState < eCLOSE_WAIT )
+ {
+ xReturn = pdTRUE;
+ }
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /* returns the actual size of MSS being used */
+ BaseType_t FreeRTOS_mss( Socket_t xSocket )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ BaseType_t xReturn;
+
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ xReturn = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else
+ {
+ /* usCurMSS is declared as uint16_t to save space. FreeRTOS_mss()
+ will often be used in signed native-size expressions cast it to
+ BaseType_t. */
+ xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.usCurMSS );
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /* HT: for internal use only: return the connection status */
+ BaseType_t FreeRTOS_connstatus( Socket_t xSocket )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ BaseType_t xReturn;
+
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ xReturn = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else
+ {
+ /* Cast it to BaseType_t */
+ xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.ucTCPState );
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /*
+ * Returns the number of bytes which can be read.
+ */
+ BaseType_t FreeRTOS_rx_size( Socket_t xSocket )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ BaseType_t xReturn;
+
+ if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
+ {
+ xReturn = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else if( pxSocket->u.xTCP.rxStream != NULL )
+ {
+ xReturn = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
+ }
+ else
+ {
+ xReturn = 0;
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP == 1 )
+
+ void FreeRTOS_netstat( void )
+ {
+ IPStackEvent_t xAskEvent;
+
+ /* Ask the IP-task to call vTCPNetStat()
+ * to avoid accessing xBoundTCPSocketsList
+ */
+ xAskEvent.eEventType = eTCPNetStat;
+ xAskEvent.pvData = ( void * ) NULL;
+ xSendEventStructToIPTask( &xAskEvent, 1000u );
+ }
+
+#endif /* ipconfigUSE_TCP */
+/*-----------------------------------------------------------*/
+
+#if( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) )
+
+ void vTCPNetStat( void )
+ {
+ /* Show a simple listing of all created sockets and their connections */
+ ListItem_t *pxIterator;
+ BaseType_t count = 0;
+
+ if( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) == pdFALSE )
+ {
+ FreeRTOS_printf( ( "PLUS-TCP not initialized\n" ) );
+ }
+ else
+ {
+ FreeRTOS_printf( ( "Prot Port IP-Remote : Port R/T Status Alive tmout Child\n" ) );
+ for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
+ pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
+ pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+ #if( ipconfigTCP_KEEP_ALIVE == 1 )
+ TickType_t age = xTaskGetTickCount() - pxSocket->u.xTCP.xLastAliveTime;
+ #else
+ TickType_t age = 0u;
+ #endif
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ void *pxHandleReceive = (void*)pxSocket->u.xTCP.pxHandleReceive;
+ #else
+ void *pxHandleReceive = (void*)NULL;
+ #endif
+ char ucChildText[16] = "";
+ if (pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN)
+ {
+ snprintf( ucChildText, sizeof( ucChildText ), " %d/%d",
+ pxSocket->u.xTCP.usChildCount,
+ pxSocket->u.xTCP.usBacklog);
+ }
+ if( age > 999999 )
+ age = 999999;
+ FreeRTOS_printf( ( "TCP %5d %-16lxip:%5d %d/%d %-13.13s %6lu %6u%s\n",
+ pxSocket->usLocalPort, /* Local port on this machine */
+ pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine */
+ pxSocket->u.xTCP.usRemotePort, /* Port on remote machine */
+ pxSocket->u.xTCP.rxStream != NULL,
+ pxSocket->u.xTCP.txStream != NULL,
+ FreeRTOS_GetTCPStateName( pxSocket->u.xTCP.ucTCPState ),
+ age,
+ pxSocket->u.xTCP.usTimeout,
+ ucChildText ) );
+ /* Remove compiler warnings if FreeRTOS_debug_printf() is not defined. */
+ ( void ) pxHandleReceive;
+ count++;
+ }
+
+ for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundUDPSocketsList );
+ pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundUDPSocketsList );
+ pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
+ {
+ /* Local port on this machine */
+ FreeRTOS_printf( ( "UDP Port %5u\n",
+ FreeRTOS_ntohs( listGET_LIST_ITEM_VALUE( pxIterator ) ) ) );
+ count++;
+ }
+
+ FreeRTOS_printf( ( "FreeRTOS_netstat: %lu sockets %lu < %lu < %d buffers free\n",
+ count,
+ uxGetMinimumFreeNetworkBuffers( ),
+ uxGetNumberOfFreeNetworkBuffers( ),
+ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) );
+ }
+ }
+
+#endif /* ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+
+ void vSocketSelect( SocketSelect_t *pxSocketSet )
+ {
+ BaseType_t xRound;
+ EventBits_t xSocketBits, xBitsToClear;
+ #if ipconfigUSE_TCP == 1
+ BaseType_t xLastRound = 1;
+ #else
+ BaseType_t xLastRound = 0;
+ #endif
+
+ /* These flags will be switched on after checking the socket status. */
+ EventBits_t xGroupBits = 0;
+ pxSocketSet->pxSocket = NULL;
+
+ for( xRound = 0; xRound <= xLastRound; xRound++ )
+ {
+ const ListItem_t *pxIterator;
+ const MiniListItem_t *pxEnd;
+ if( xRound == 0 )
+ {
+ pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundUDPSocketsList );
+ }
+ #if ipconfigUSE_TCP == 1
+ else
+ {
+ pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList );
+ }
+ #endif /* ipconfigUSE_TCP == 1 */
+ for( pxIterator = ( const ListItem_t * ) ( listGET_NEXT( pxEnd ) );
+ pxIterator != ( const ListItem_t * ) pxEnd;
+ pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+ if( pxSocket->pxSocketSet != pxSocketSet )
+ {
+ /* Socket does not belong to this select group. */
+ continue;
+ }
+ xSocketBits = 0;
+
+ #if( ipconfigUSE_TCP == 1 )
+ if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP )
+ {
+ /* Check if the socket has already been accepted by the
+ owner. If not, it is useless to return it from a
+ select(). */
+ BaseType_t bAccepted = pdFALSE;
+
+ if( pxSocket->u.xTCP.bits.bPassQueued == pdFALSE_UNSIGNED )
+ {
+ if( pxSocket->u.xTCP.bits.bPassAccept == pdFALSE_UNSIGNED )
+ {
+ bAccepted = pdTRUE;
+ }
+ }
+
+ /* Is the set owner interested in READ events? */
+ if( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 )
+ {
+ if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
+ {
+ if( ( pxSocket->u.xTCP.pxPeerSocket != NULL ) && ( pxSocket->u.xTCP.pxPeerSocket->u.xTCP.bits.bPassAccept != 0 ) )
+ {
+ xSocketBits |= eSELECT_READ;
+ }
+ }
+ else if( ( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
+ {
+ /* This socket has the re-use flag. After connecting it turns into
+ aconnected socket. Set the READ event, so that accept() will be called. */
+ xSocketBits |= eSELECT_READ;
+ }
+ else if( ( bAccepted != 0 ) && ( FreeRTOS_recvcount( pxSocket ) > 0 ) )
+ {
+ xSocketBits |= eSELECT_READ;
+ }
+ }
+ /* Is the set owner interested in EXCEPTION events? */
+ if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )
+ {
+ if( ( pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT ) || ( pxSocket->u.xTCP.ucTCPState == eCLOSED ) )
+ {
+ xSocketBits |= eSELECT_EXCEPT;
+ }
+ }
+
+ /* Is the set owner interested in WRITE events? */
+ if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )
+ {
+ BaseType_t bMatch = pdFALSE;
+
+ if( bAccepted != 0 )
+ {
+ if( FreeRTOS_tx_space( pxSocket ) > 0 )
+ {
+ bMatch = pdTRUE;
+ }
+ }
+
+ if( bMatch == pdFALSE )
+ {
+ if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) &&
+ ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) &&
+ ( pxSocket->u.xTCP.bits.bConnPassed == pdFALSE_UNSIGNED ) )
+ {
+ pxSocket->u.xTCP.bits.bConnPassed = pdTRUE_UNSIGNED;
+ bMatch = pdTRUE;
+ }
+ }
+
+ if( bMatch != pdFALSE )
+ {
+ xSocketBits |= eSELECT_WRITE;
+ }
+ }
+ }
+ else
+ #endif /* ipconfigUSE_TCP == 1 */
+ {
+ /* Select events for UDP are simpler. */
+ if( ( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) &&
+ ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U ) )
+ {
+ xSocketBits |= eSELECT_READ;
+ }
+ /* The WRITE and EXCEPT bits are not used for UDP */
+ } /* if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ) */
+
+ /* Each socket keeps its own event flags, which are looked-up
+ by FreeRTOS_FD_ISSSET() */
+ pxSocket->xSocketBits = xSocketBits;
+
+ /* The ORed value will be used to set the bits in the event
+ group. */
+ xGroupBits |= xSocketBits;
+
+ } /* for( pxIterator ... ) */
+ } /* for( xRound = 0; xRound <= xLastRound; xRound++ ) */
+
+ xBitsToClear = xEventGroupGetBits( pxSocketSet->xSelectGroup );
+
+ /* Now set the necessary bits. */
+ xBitsToClear = ( xBitsToClear & ~xGroupBits ) & eSELECT_ALL;
+
+ #if( ipconfigSUPPORT_SIGNALS != 0 )
+ {
+ /* Maybe the socketset was signalled, but don't
+ clear the 'eSELECT_INTR' bit here, as it will be used
+ and cleared in FreeRTOS_select(). */
+ xBitsToClear &= ( EventBits_t ) ~eSELECT_INTR;
+ }
+ #endif /* ipconfigSUPPORT_SIGNALS */
+
+ if( xBitsToClear != 0 )
+ {
+ xEventGroupClearBits( pxSocketSet->xSelectGroup, xBitsToClear );
+ }
+
+ /* Now include eSELECT_CALL_IP to wakeup the caller. */
+ xEventGroupSetBits( pxSocketSet->xSelectGroup, xGroupBits | eSELECT_CALL_IP );
+ }
+
+#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigSUPPORT_SIGNALS != 0 )
+
+ /* Send a signal to the task which reads from this socket. */
+ BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ BaseType_t xReturn;
+
+ if( pxSocket == NULL )
+ {
+ xReturn = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ else
+ #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+ if( ( pxSocket->pxSocketSet != NULL ) && ( pxSocket->pxSocketSet->xSelectGroup != NULL ) )
+ {
+ xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, eSELECT_INTR );
+ xReturn = 0;
+ }
+ else
+ #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
+ if( pxSocket->xEventGroup != NULL )
+ {
+ xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_INTR );
+ xReturn = 0;
+ }
+ else
+ {
+ xReturn = -pdFREERTOS_ERRNO_EINVAL;
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigSUPPORT_SIGNALS */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigSUPPORT_SIGNALS != 0 )
+
+ /* Send a signal to the task which reads from this socket (FromISR version). */
+ BaseType_t FreeRTOS_SignalSocketFromISR( Socket_t xSocket, BaseType_t *pxHigherPriorityTaskWoken )
+ {
+ FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
+ BaseType_t xReturn;
+ IPStackEvent_t xEvent;
+ extern QueueHandle_t xNetworkEventQueue;
+
+ configASSERT( pxSocket != NULL );
+ configASSERT( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP );
+ configASSERT( pxSocket->xEventGroup );
+
+ xEvent.eEventType = eSocketSignalEvent;
+ xEvent.pvData = ( void * )pxSocket;
+
+ /* The IP-task will call FreeRTOS_SignalSocket for this socket. */
+ xReturn = xQueueSendToBackFromISR( xNetworkEventQueue, &xEvent, pxHigherPriorityTaskWoken );
+
+ return xReturn;
+ }
+
+#endif /* ipconfigSUPPORT_SIGNALS */
+/*-----------------------------------------------------------*/
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c
new file mode 100644
index 000000000..0e8786f0d
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c
@@ -0,0 +1,231 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+
+/*
+ * uxStreamBufferAdd( )
+ * Adds data to a stream buffer. If uxOffset > 0, data will be written at
+ * an offset from uxHead while uxHead will not be moved yet. This possibility
+ * will be used when TCP data is received while earlier data is still missing.
+ * If 'pucData' equals NULL, the function is called to advance 'uxHead' only.
+ */
+size_t uxStreamBufferAdd( StreamBuffer_t *pxBuffer, size_t uxOffset, const uint8_t *pucData, size_t uxCount )
+{
+size_t uxSpace, uxNextHead, uxFirst;
+
+ uxSpace = uxStreamBufferGetSpace( pxBuffer );
+
+ /* If uxOffset > 0, items can be placed in front of uxHead */
+ if( uxSpace > uxOffset )
+ {
+ uxSpace -= uxOffset;
+ }
+ else
+ {
+ uxSpace = 0u;
+ }
+
+ /* The number of bytes that can be written is the minimum of the number of
+ bytes requested and the number available. */
+ uxCount = FreeRTOS_min_uint32( uxSpace, uxCount );
+
+ if( uxCount != 0u )
+ {
+ uxNextHead = pxBuffer->uxHead;
+
+ if( uxOffset != 0u )
+ {
+ /* ( uxOffset > 0 ) means: write in front if the uxHead marker */
+ uxNextHead += uxOffset;
+ if( uxNextHead >= pxBuffer->LENGTH )
+ {
+ uxNextHead -= pxBuffer->LENGTH;
+ }
+ }
+
+ if( pucData != NULL )
+ {
+ /* Calculate the number of bytes that can be added in the first
+ write - which may be less than the total number of bytes that need
+ to be added if the buffer will wrap back to the beginning. */
+ uxFirst = FreeRTOS_min_uint32( pxBuffer->LENGTH - uxNextHead, uxCount );
+
+ /* Write as many bytes as can be written in the first write. */
+ memcpy( ( void* ) ( pxBuffer->ucArray + uxNextHead ), pucData, uxFirst );
+
+ /* If the number of bytes written was less than the number that
+ could be written in the first write... */
+ if( uxCount > uxFirst )
+ {
+ /* ...then write the remaining bytes to the start of the
+ buffer. */
+ memcpy( ( void * )pxBuffer->ucArray, pucData + uxFirst, uxCount - uxFirst );
+ }
+ }
+
+ if( uxOffset == 0u )
+ {
+ /* ( uxOffset == 0 ) means: write at uxHead position */
+ uxNextHead += uxCount;
+ if( uxNextHead >= pxBuffer->LENGTH )
+ {
+ uxNextHead -= pxBuffer->LENGTH;
+ }
+ pxBuffer->uxHead = uxNextHead;
+ }
+
+ if( xStreamBufferLessThenEqual( pxBuffer, pxBuffer->uxFront, uxNextHead ) != pdFALSE )
+ {
+ /* Advance the front pointer */
+ pxBuffer->uxFront = uxNextHead;
+ }
+ }
+
+ return uxCount;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * uxStreamBufferGet( )
+ * 'uxOffset' can be used to read data located at a certain offset from 'lTail'.
+ * If 'pucData' equals NULL, the function is called to advance 'lTail' only.
+ * if 'xPeek' is pdTRUE, or if 'uxOffset' is non-zero, the 'lTail' pointer will
+ * not be advanced.
+ */
+size_t uxStreamBufferGet( StreamBuffer_t *pxBuffer, size_t uxOffset, uint8_t *pucData, size_t uxMaxCount, BaseType_t xPeek )
+{
+size_t uxSize, uxCount, uxFirst, uxNextTail;
+
+ /* How much data is available? */
+ uxSize = uxStreamBufferGetSize( pxBuffer );
+
+ if( uxSize > uxOffset )
+ {
+ uxSize -= uxOffset;
+ }
+ else
+ {
+ uxSize = 0u;
+ }
+
+ /* Use the minimum of the wanted bytes and the available bytes. */
+ uxCount = FreeRTOS_min_uint32( uxSize, uxMaxCount );
+
+ if( uxCount > 0u )
+ {
+ uxNextTail = pxBuffer->uxTail;
+
+ if( uxOffset != 0u )
+ {
+ uxNextTail += uxOffset;
+ if( uxNextTail >= pxBuffer->LENGTH )
+ {
+ uxNextTail -= pxBuffer->LENGTH;
+ }
+ }
+
+ if( pucData != NULL )
+ {
+ /* Calculate the number of bytes that can be read - which may be
+ less than the number wanted if the data wraps around to the start of
+ the buffer. */
+ uxFirst = FreeRTOS_min_uint32( pxBuffer->LENGTH - uxNextTail, uxCount );
+
+ /* Obtain the number of bytes it is possible to obtain in the first
+ read. */
+ memcpy( pucData, pxBuffer->ucArray + uxNextTail, uxFirst );
+
+ /* If the total number of wanted bytes is greater than the number
+ that could be read in the first read... */
+ if( uxCount > uxFirst )
+ {
+ /*...then read the remaining bytes from the start of the buffer. */
+ memcpy( pucData + uxFirst, pxBuffer->ucArray, uxCount - uxFirst );
+ }
+ }
+
+ if( ( xPeek == pdFALSE ) && ( uxOffset == 0UL ) )
+ {
+ /* Move the tail pointer to effecively remove the data read from
+ the buffer. */
+ uxNextTail += uxCount;
+
+ if( uxNextTail >= pxBuffer->LENGTH )
+ {
+ uxNextTail -= pxBuffer->LENGTH;
+ }
+
+ pxBuffer->uxTail = uxNextTail;
+ }
+ }
+
+ return uxCount;
+}
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c
new file mode 100644
index 000000000..19ddf53b5
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c
@@ -0,0 +1,3359 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*
+ * FreeRTOS_TCP_IP.c
+ * Module which handles the TCP connections for FreeRTOS+TCP.
+ * It depends on FreeRTOS_TCP_WIN.c, which handles the TCP windowing
+ * schemes.
+ *
+ * Endianness: in this module all ports and IP addresses are stored in
+ * host byte-order, except fields in the IP-packets
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.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_UDP_IP.h"
+#include "FreeRTOS_TCP_IP.h"
+#include "FreeRTOS_DHCP.h"
+#include "NetworkInterface.h"
+#include "NetworkBufferManagement.h"
+#include "FreeRTOS_ARP.h"
+#include "FreeRTOS_TCP_WIN.h"
+
+
+/* Just make sure the contents doesn't get compiled if TCP is not enabled. */
+#if ipconfigUSE_TCP == 1
+
+/* This compile-time test was moved to here because some macro's
+were unknown within 'FreeRTOSIPConfigDefaults.h'. It tests whether
+the defined MTU size can contain at ;east a complete TCP packet. */
+
+#if ( ( ipconfigTCP_MSS + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) > ipconfigNETWORK_MTU )
+ #error The ipconfigTCP_MSS setting in FreeRTOSIPConfig.h is too large.
+#endif
+
+/*
+ * The meaning of the TCP flags:
+ */
+#define ipTCP_FLAG_FIN 0x0001u /* No more data from sender */
+#define ipTCP_FLAG_SYN 0x0002u /* Synchronize sequence numbers */
+#define ipTCP_FLAG_RST 0x0004u /* Reset the connection */
+#define ipTCP_FLAG_PSH 0x0008u /* Push function: please push buffered data to the recv application */
+#define ipTCP_FLAG_ACK 0x0010u /* Acknowledgment field is significant */
+#define ipTCP_FLAG_URG 0x0020u /* Urgent pointer field is significant */
+#define ipTCP_FLAG_ECN 0x0040u /* ECN-Echo */
+#define ipTCP_FLAG_CWR 0x0080u /* Congestion Window Reduced */
+#define ipTCP_FLAG_NS 0x0100u /* ECN-nonce concealment protection */
+#define ipTCP_FLAG_RSV 0x0E00u /* Reserved, keep 0 */
+
+/* A mask to filter all protocol flags. */
+#define ipTCP_FLAG_CTRL 0x001Fu
+
+/*
+ * A few values of the TCP options:
+ */
+#define TCP_OPT_END 0u /* End of TCP options list */
+#define TCP_OPT_NOOP 1u /* "No-operation" TCP option */
+#define TCP_OPT_MSS 2u /* Maximum segment size TCP option */
+#define TCP_OPT_WSOPT 3u /* TCP Window Scale Option (3-byte long) */
+#define TCP_OPT_SACK_P 4u /* Advertize that SACK is permitted */
+#define TCP_OPT_SACK_A 5u /* SACK option with first/last */
+#define TCP_OPT_TIMESTAMP 8u /* Time-stamp option */
+
+#define TCP_OPT_MSS_LEN 4u /* Length of TCP MSS option. */
+#define TCP_OPT_WSOPT_LEN 3u /* Length of TCP WSOPT option. */
+
+#define TCP_OPT_TIMESTAMP_LEN 10 /* fixed length of the time-stamp option */
+
+#ifndef ipconfigTCP_ACK_EARLIER_PACKET
+ #define ipconfigTCP_ACK_EARLIER_PACKET 1
+#endif
+
+/*
+ * The macro NOW_CONNECTED() is use to determine if the connection makes a
+ * transition from connected to non-connected and vice versa.
+ * NOW_CONNECTED() returns true when the status has one of these values:
+ * eESTABLISHED, eFIN_WAIT_1, eFIN_WAIT_2, eCLOSING, eLAST_ACK, eTIME_WAIT
+ * Technically the connection status is closed earlier, but the library wants
+ * to prevent that the socket will be deleted before the last ACK has been
+ * and thus causing a 'RST' packet on either side.
+ */
+#define NOW_CONNECTED( status )\
+ ( ( status >= eESTABLISHED ) && ( status != eCLOSE_WAIT ) )
+
+/*
+ * The highest 4 bits in the TCP offset byte indicate the total length of the
+ * TCP header, divided by 4.
+ */
+#define VALID_BITS_IN_TCP_OFFSET_BYTE ( 0xF0u )
+
+/*
+ * Acknowledgements to TCP data packets may be delayed as long as more is being expected.
+ * A normal delay would be 200ms. Here a much shorter delay of 20 ms is being used to
+ * gain performance.
+ */
+#define DELAYED_ACK_SHORT_DELAY_MS ( 2 )
+#define DELAYED_ACK_LONGER_DELAY_MS ( 20 )
+
+/*
+ * The MSS (Maximum Segment Size) will be taken as large as possible. However, packets with
+ * an MSS of 1460 bytes won't be transported through the internet. The MSS will be reduced
+ * to 1400 bytes.
+ */
+#define REDUCED_MSS_THROUGH_INTERNET ( 1400 )
+
+/*
+ * Each time a new TCP connection is being made, a new Initial Sequence Number shall be used.
+ * The variable 'ulNextInitialSequenceNumber' will be incremented with a recommended value
+ * of 0x102.
+ */
+#define INITIAL_SEQUENCE_NUMBER_INCREMENT ( 0x102UL )
+
+/*
+ * When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
+ * the number 5 (words) in the higher niblle of the TCP-offset byte.
+ */
+#define TCP_OFFSET_LENGTH_BITS ( 0xf0u )
+#define TCP_OFFSET_STANDARD_LENGTH ( 0x50u )
+
+/*
+ * Each TCP socket is checked regularly to see if it can send data packets.
+ * By default, the maximum number of packets sent during one check is limited to 8.
+ * This amount may be further limited by setting the socket's TX window size.
+ */
+#if( !defined( SEND_REPEATED_COUNT ) )
+ #define SEND_REPEATED_COUNT ( 8 )
+#endif /* !defined( SEND_REPEATED_COUNT ) */
+
+/*
+ * Define a maximum perdiod of time (ms) to leave a TCP-socket unattended.
+ * When a TCP timer expires, retries and keep-alive messages will be checked.
+ */
+#ifndef tcpMAXIMUM_TCP_WAKEUP_TIME_MS
+ #define tcpMAXIMUM_TCP_WAKEUP_TIME_MS 20000u
+#endif
+
+/*
+ * The names of the different TCP states may be useful in logging.
+ */
+#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
+ static const char *pcStateNames[] = {
+ "eCLOSED",
+ "eTCP_LISTEN",
+ "eCONNECT_SYN",
+ "eSYN_FIRST",
+ "eSYN_RECEIVED",
+ "eESTABLISHED",
+ "eFIN_WAIT_1",
+ "eFIN_WAIT_2",
+ "eCLOSE_WAIT",
+ "eCLOSING",
+ "eLAST_ACK",
+ "eTIME_WAIT",
+ "eUNKNOWN",
+};
+#endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) */
+
+/*
+ * Returns true if the socket must be checked. Non-active sockets are waiting
+ * for user action, either connect() or close().
+ */
+static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus );
+
+/*
+ * Either sends a SYN or calls prvTCPSendRepeated (for regular messages).
+ */
+static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * Try to send a series of messages.
+ */
+static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
+
+/*
+ * Return or send a packet to the other party.
+ */
+static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
+ uint32_t ulLen, BaseType_t xReleaseAfterSend );
+
+/*
+ * Initialise the data structures which keep track of the TCP windowing system.
+ */
+static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * Let ARP look-up the MAC-address of the peer and initialise the first SYN
+ * packet.
+ */
+static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket );
+
+#if( ipconfigHAS_DEBUG_PRINTF != 0 )
+ /*
+ * For logging and debugging: make a string showing the TCP flags.
+ */
+ static const char *prvTCPFlagMeaning( UBaseType_t xFlags);
+#endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
+
+/*
+ * Parse the TCP option(s) received, if present.
+ */
+static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+/*
+ * Set the initial properties in the options fields, like the preferred
+ * value of MSS and whether SACK allowed. Will be transmitted in the state
+ * 'eCONNECT_SYN'.
+ */
+static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket );
+
+/*
+ * For anti-hang protection and TCP keep-alive messages. Called in two places:
+ * after receiving a packet and after a state change. The socket's alive timer
+ * may be reset.
+ */
+static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * Prepare an outgoing message, if anything has to be sent.
+ */
+static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength );
+
+/*
+ * Calculate when this socket needs to be checked to do (re-)transmissions.
+ */
+static TickType_t prvTCPNextTimeout( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * The API FreeRTOS_send() adds data to the TX stream. Add
+ * this data to the windowing system to it can be transmitted.
+ */
+static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * Called to handle the closure of a TCP connection.
+ */
+static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+#if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
+ static UBaseType_t prvTCPSetTimeStamp( BaseType_t lOffset, FreeRTOS_Socket_t *pxSocket, TCPHeader_t *pxTCPHeader );
+#endif
+
+/*
+ * Called from prvTCPHandleState(). Find the TCP payload data and check and
+ * return its length.
+ */
+static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData );
+
+/*
+ * Called from prvTCPHandleState(). Check if the payload data may be accepted.
+ * If so, it will be added to the socket's reception queue.
+ */
+static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
+ NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength );
+
+/*
+ * Set the TCP options (if any) for the outgoing packet.
+ */
+static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+/*
+ * Called from prvTCPHandleState() as long as the TCP status is eSYN_RECEIVED to
+ * eCONNECT_SYN.
+ */
+static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+ uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
+
+/*
+ * Called from prvTCPHandleState() as long as the TCP status is eESTABLISHED.
+ */
+static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+ uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );
+
+/*
+ * Called from prvTCPHandleState(). There is data to be sent.
+ * If ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will
+ * be checked if it would better be postponed for efficiency.
+ */
+static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+ uint32_t ulReceiveLength, BaseType_t xSendLength );
+
+/*
+ * The heart of all: check incoming packet for valid data and acks and do what
+ * is necessary in each state.
+ */
+static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );
+
+/*
+ * Reply to a peer with the RST flag on, in case a packet can not be handled.
+ */
+static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+/*
+ * Set the initial value for MSS (Maximum Segment Size) to be used.
+ */
+static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * Return either a newly created socket, or the current socket in a connected
+ * state (depends on the 'bReuseSocket' flag).
+ */
+static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+/*
+ * After a listening socket receives a new connection, it may duplicate itself.
+ * The copying takes place in prvTCPSocketCopy.
+ */
+static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * prvTCPStatusAgeCheck() will see if the socket has been in a non-connected
+ * state for too long. If so, the socket will be closed, and -1 will be
+ * returned.
+ */
+#if( ipconfigTCP_HANG_PROTECTION == 1 )
+ static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket );
+#endif
+
+static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
+ int32_t lDataLen, UBaseType_t uxOptionsLength );
+
+#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
+ const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState );
+#endif
+
+#if( ipconfigUSE_TCP_WIN != 0 )
+ static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket );
+#endif
+
+/*-----------------------------------------------------------*/
+
+/* Initial Sequence Number, i.e. the next initial sequence number that will be
+used when a new connection is opened. The value should be randomized to prevent
+attacks from outside (spoofing). */
+uint32_t ulNextInitialSequenceNumber = 0ul;
+
+/*-----------------------------------------------------------*/
+
+/* prvTCPSocketIsActive() returns true if the socket must be checked.
+ * Non-active sockets are waiting for user action, either connect()
+ * or close(). */
+static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus )
+{
+ switch( uxStatus )
+ {
+ case eCLOSED:
+ case eCLOSE_WAIT:
+ case eFIN_WAIT_2:
+ case eCLOSING:
+ case eTIME_WAIT:
+ return pdFALSE;
+ default:
+ return pdTRUE;
+ }
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigTCP_HANG_PROTECTION == 1 )
+
+ static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket )
+ {
+ BaseType_t xResult;
+ switch( pxSocket->u.xTCP.ucTCPState )
+ {
+ case eESTABLISHED:
+ /* If the 'ipconfigTCP_KEEP_ALIVE' option is enabled, sockets in
+ state ESTABLISHED can be protected using keep-alive messages. */
+ xResult = pdFALSE;
+ break;
+ case eCLOSED:
+ case eTCP_LISTEN:
+ case eCLOSE_WAIT:
+ /* These 3 states may last for ever, up to the owner. */
+ xResult = pdFALSE;
+ break;
+ default:
+ /* All other (non-connected) states will get anti-hanging
+ protection. */
+ xResult = pdTRUE;
+ break;
+ }
+ if( xResult != pdFALSE )
+ {
+ /* How much time has past since the last active moment which is
+ defined as A) a state change or B) a packet has arrived. */
+ TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastActTime;
+
+ /* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. */
+ if( xAge > ( ipconfigTCP_HANG_PROTECTION_TIME * configTICK_RATE_HZ ) )
+ {
+ #if( ipconfigHAS_DEBUG_PRINTF == 1 )
+ {
+ FreeRTOS_debug_printf( ( "Inactive socket closed: port %u rem %lxip:%u status %s\n",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.ulRemoteIP,
+ pxSocket->u.xTCP.usRemotePort,
+ FreeRTOS_GetTCPStateName( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) ) );
+ }
+ #endif /* ipconfigHAS_DEBUG_PRINTF */
+
+ /* Move to eCLOSE_WAIT, user may close the socket. */
+ vTCPStateChange( pxSocket, eCLOSE_WAIT );
+
+ /* When 'bPassQueued' true, this socket is an orphan until it
+ gets connected. */
+ if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
+ {
+ if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
+ {
+ /* As it did not get connected, and the user can never
+ accept() it anymore, it will be deleted now. Called from
+ the IP-task, so it's safe to call the internal Close
+ function: vSocketClose(). */
+ vSocketClose( pxSocket );
+ }
+ /* Return a negative value to tell to inform the caller
+ xTCPTimerCheck()
+ that the socket got closed and may not be accessed anymore. */
+ xResult = -1;
+ }
+ }
+ }
+ return xResult;
+ }
+ /*-----------------------------------------------------------*/
+
+#endif
+
+/*
+ * As soon as a TCP socket timer expires, this function xTCPSocketCheck
+ * will be called (from xTCPTimerCheck)
+ * It can send a delayed ACK or new data
+ * Sequence of calling (normally) :
+ * IP-Task:
+ * xTCPTimerCheck() // Check all sockets ( declared in FreeRTOS_Sockets.c )
+ * xTCPSocketCheck() // Either send a delayed ACK or call prvTCPSendPacket()
+ * prvTCPSendPacket() // Either send a SYN or call prvTCPSendRepeated ( regular messages )
+ * prvTCPSendRepeated() // Send at most 8 messages on a row
+ * prvTCPReturnPacket() // Prepare for returning
+ * xNetworkInterfaceOutput() // Sends data to the NIC ( declared in portable/NetworkInterface/xxx )
+ */
+BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket )
+{
+BaseType_t xResult = 0;
+BaseType_t xReady = pdFALSE;
+
+ if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) )
+ {
+ /* The API FreeRTOS_send() might have added data to the TX stream. Add
+ this data to the windowing system so it can be transmitted. */
+ prvTCPAddTxData( pxSocket );
+ }
+
+ #if( ipconfigUSE_TCP_WIN == 1 )
+ {
+ if( pxSocket->u.xTCP.pxAckMessage != NULL )
+ {
+ /* The first task of this regular socket check is to send-out delayed
+ ACK's. */
+ if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED )
+ {
+ /* Earlier data was received but not yet acknowledged. This
+ function is called when the TCP timer for the socket expires, the
+ ACK may be sent now. */
+ if( pxSocket->u.xTCP.ucTCPState != eCLOSED )
+ {
+ if( xTCPWindowLoggingLevel > 1 && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
+ {
+ FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %u)\n",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.usRemotePort,
+ pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
+ pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber,
+ ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) );
+ }
+
+ prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER, ipconfigZERO_COPY_TX_DRIVER );
+
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* The ownership has been passed to the SEND routine,
+ clear the pointer to it. */
+ pxSocket->u.xTCP.pxAckMessage = NULL;
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+ }
+ if( prvTCPNextTimeout( pxSocket ) > 1 )
+ {
+ /* Tell the code below that this function is ready. */
+ xReady = pdTRUE;
+ }
+ }
+ else
+ {
+ /* The user wants to perform an active shutdown(), skip sending
+ the delayed ACK. The function prvTCPSendPacket() will send the
+ FIN along with the ACK's. */
+ }
+
+ if( pxSocket->u.xTCP.pxAckMessage != NULL )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
+ pxSocket->u.xTCP.pxAckMessage = NULL;
+ }
+ }
+ }
+ #endif /* ipconfigUSE_TCP_WIN */
+
+ if( xReady == pdFALSE )
+ {
+ /* The second task of this regular socket check is sending out data. */
+ if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) ||
+ ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) )
+ {
+ prvTCPSendPacket( pxSocket );
+ }
+
+ /* Set the time-out for the next wakeup for this socket. */
+ prvTCPNextTimeout( pxSocket );
+
+ #if( ipconfigTCP_HANG_PROTECTION == 1 )
+ {
+ /* In all (non-connected) states in which keep-alive messages can not be sent
+ the anti-hang protocol will close sockets that are 'hanging'. */
+ xResult = prvTCPStatusAgeCheck( pxSocket );
+ }
+ #endif
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvTCPSendPacket() will be called when the socket time-out has been reached.
+ * It is only called by xTCPSocketCheck().
+ */
+static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket )
+{
+int32_t lResult = 0;
+UBaseType_t uxOptionsLength;
+TCPPacket_t *pxTCPPacket;
+NetworkBufferDescriptor_t *pxNetworkBuffer;
+
+ if( pxSocket->u.xTCP.ucTCPState != eCONNECT_SYN )
+ {
+ /* The connection is in a state other than SYN. */
+ pxNetworkBuffer = NULL;
+
+ /* prvTCPSendRepeated() will only create a network buffer if necessary,
+ i.e. when data must be sent to the peer. */
+ lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
+
+ if( pxNetworkBuffer != NULL )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ }
+ }
+ else
+ {
+ if( pxSocket->u.xTCP.ucRepCount >= 3u )
+ {
+ /* The connection is in the SYN status. The packet will be repeated
+ to most 3 times. When there is no response, the socket get the
+ status 'eCLOSE_WAIT'. */
+ FreeRTOS_debug_printf( ( "Connect: giving up %lxip:%u\n",
+ pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
+ pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
+ vTCPStateChange( pxSocket, eCLOSE_WAIT );
+ }
+ else if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) || ( prvTCPPrepareConnect( pxSocket ) == pdTRUE ) )
+ {
+ /* Or else, if the connection has been prepared, or can be prepared
+ now, proceed to send the packet with the SYN flag.
+ prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if
+ the Ethernet address of the peer or the gateway is found. */
+ pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
+
+ #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
+ {
+ /* When TCP time stamps are enabled, but they will only be applied
+ if the peer is outside the netmask, usually on the internet.
+ Packages sent on a LAN are usually too big to carry time stamps. */
+ if( ( ( pxSocket->u.xTCP.ulRemoteIP ^ FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) ) & xNetworkAddressing.ulNetMask ) != 0ul )
+ {
+ pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps = pdTRUE_UNSIGNED;
+ }
+ }
+ #endif
+
+ /* About to send a SYN packet. Call prvSetSynAckOptions() to set
+ the proper options: The size of MSS and whether SACK's are
+ allowed. */
+ uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
+
+ /* Return the number of bytes to be sent. */
+ lResult = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+
+ /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
+ uxOptionsLength is always a multiple of 4. The complete expression
+ would be:
+ ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
+ pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+
+ /* Repeat Count is used for a connecting socket, to limit the number
+ of tries. */
+ pxSocket->u.xTCP.ucRepCount++;
+
+ /* Send the SYN message to make a connection. The messages is
+ stored in the socket field 'xPacket'. It will be wrapped in a
+ pseudo network buffer descriptor before it will be sent. */
+ prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE );
+ }
+ }
+
+ /* Return the total number of bytes sent. */
+ return lResult;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvTCPSendRepeated will try to send a series of messages, as long as there is
+ * data to be sent and as long as the transmit window isn't full.
+ */
+static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
+{
+UBaseType_t uxIndex;
+int32_t lResult = 0;
+UBaseType_t uxOptionsLength = 0u;
+int32_t xSendLength;
+
+ for( uxIndex = 0u; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ )
+ {
+ /* prvTCPPrepareSend() might allocate a network buffer if there is data
+ to be sent. */
+ xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
+ if( xSendLength <= 0 )
+ {
+ break;
+ }
+
+ /* And return the packet to the peer. */
+ prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
+
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ *ppxNetworkBuffer = NULL;
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+ lResult += xSendLength;
+ }
+
+ /* Return the total number of bytes sent. */
+ return lResult;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Return (or send) a packet the the peer. The data is stored in pxBuffer,
+ * which may either point to a real network buffer or to a TCP socket field
+ * called 'xTCP.xPacket'. A temporary xNetworkBuffer will be used to pass
+ * the data to the NIC.
+ */
+static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulLen, BaseType_t xReleaseAfterSend )
+{
+TCPPacket_t * pxTCPPacket;
+IPHeader_t *pxIPHeader;
+EthernetHeader_t *pxEthernetHeader;
+uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize;
+TCPWindow_t *pxTCPWindow;
+NetworkBufferDescriptor_t xTempBuffer;
+/* For sending, a pseudo network buffer will be used, as explained above. */
+
+ if( pxNetworkBuffer == NULL )
+ {
+ memset( &xTempBuffer, '\0', sizeof( xTempBuffer ) );
+ pxNetworkBuffer = &xTempBuffer;
+
+ xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
+ xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
+ }
+
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ if( xReleaseAfterSend == pdFALSE )
+ {
+ pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
+ if( pxNetworkBuffer == NULL )
+ {
+ FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );
+ }
+ xReleaseAfterSend = pdTRUE;
+ }
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+ if( pxNetworkBuffer != NULL )
+ {
+ pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+ pxIPHeader = &pxTCPPacket->xIPHeader;
+ pxEthernetHeader = &pxTCPPacket->xEthernetHeader;
+
+ /* Fill the packet, using hton translations. */
+ if( pxSocket != NULL )
+ {
+ /* Calculate the space in the RX buffer in order to advertise the
+ size of this socket's reception window. */
+ pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
+
+ if( pxSocket->u.xTCP.rxStream != NULL )
+ {
+ /* An RX stream was created already, see how much space is
+ available. */
+ ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
+ }
+ else
+ {
+ /* No RX stream has been created, the full stream size is
+ available. */
+ ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
+ }
+
+ /* Take the minimum of the RX buffer space and the RX window size. */
+ ulSpace = FreeRTOS_min_uint32( pxSocket->u.xTCP.ulRxCurWinSize, pxTCPWindow->xSize.ulRxWindowLength );
+
+ if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )
+ {
+ /* The low-water mark was reached, meaning there was little
+ space left. The socket will wait until the application has read
+ or flushed the incoming data, and 'zero-window' will be
+ advertised. */
+ ulSpace = 0u;
+ }
+
+ /* If possible, advertise an RX window size of at least 1 MSS, otherwise
+ the peer might start 'zero window probing', i.e. sending small packets
+ (1, 2, 4, 8... bytes). */
+ if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )
+ {
+ ulSpace = pxSocket->u.xTCP.usCurMSS;
+ }
+
+ /* Avoid overflow of the 16-bit win field. */
+ #if( ipconfigUSE_TCP_WIN != 0 )
+ {
+ ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );
+ }
+ #else
+ {
+ ulWinSize = ulSpace;
+ }
+ #endif
+ if( ulWinSize > 0xfffcUL )
+ {
+ ulWinSize = 0xfffcUL;
+ }
+
+ pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );
+
+ #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+ {
+ if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )
+ {
+ if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )
+ {
+ size_t uxFrontSpace;
+
+ if(pxSocket->u.xTCP.rxStream != NULL)
+ {
+ uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;
+ }
+ else
+ {
+ uxFrontSpace = 0u;
+ }
+
+ FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",
+ pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",
+ pxSocket->u.xTCP.ulRemoteIP,
+ pxSocket->u.xTCP.usRemotePort,
+ pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,
+ (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );
+ }
+ }
+ }
+ #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
+
+ /* The new window size has been advertised, switch off the flag. */
+ pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;
+
+ /* Later on, when deciding to delay an ACK, a precise estimate is needed
+ of the free RX space. At this moment, 'ulHighestRxAllowed' would be the
+ highest sequence number minus 1 that the socket will accept. */
+ pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;
+
+ #if( ipconfigTCP_KEEP_ALIVE == 1 )
+ if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )
+ {
+ /* Sending a keep-alive packet, send the current sequence number
+ minus 1, which will be recognised as a keep-alive packet an
+ responded to by acknowledging the last byte. */
+ pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
+ pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;
+
+ pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;
+ pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
+ }
+ else
+ #endif
+ {
+ pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );
+
+ if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )
+ {
+ /* Suppress FIN in case this packet carries earlier data to be
+ retransmitted. */
+ uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );
+ if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )
+ {
+ pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );
+ FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",
+ pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+ ulDataLen,
+ pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );
+ }
+ }
+ }
+
+ /* Tell which sequence number is expected next time */
+ pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );
+ }
+ else
+ {
+ /* Sending data without a socket, probably replying with a RST flag
+ Just swap the two sequence numbers. */
+ vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );
+ }
+
+ pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
+ pxIPHeader->usLength = FreeRTOS_htons( ulLen );
+ if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
+ {
+ /* When pxSocket is NULL, this function is called by prvTCPSendReset()
+ and the IP-addresses must be swapped.
+ Also swap the IP-addresses in case the IP-tack doesn't have an
+ IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */
+ ulSourceAddress = pxIPHeader->ulDestinationIPAddress;
+ }
+ else
+ {
+ ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;
+ }
+ pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
+ pxIPHeader->ulSourceIPAddress = ulSourceAddress;
+ vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );
+
+ /* Just an increasing number. */
+ pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
+ usPacketIdentifier++;
+ pxIPHeader->usFragmentOffset = 0u;
+
+ #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
+ {
+ /* calculate the IP header checksum, in case the driver won't do that. */
+ pxIPHeader->usHeaderChecksum = 0x00u;
+ pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
+ pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
+
+ /* calculate the TCP checksum for an outgoing packet. */
+ usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pdTRUE );
+
+ /* A calculated checksum of 0 must be inverted as 0 means the checksum
+ is disabled. */
+ if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )
+ {
+ pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;
+ }
+ }
+ #endif
+
+ #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
+ {
+ pxNetworkBuffer->pxNextBuffer = NULL;
+ }
+ #endif
+
+ /* Important: tell NIC driver how many bytes must be sent. */
+ pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;
+
+ /* Fill in the destination MAC addresses. */
+ memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),
+ sizeof( pxEthernetHeader->xDestinationAddress ) );
+
+ /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */
+ memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
+
+ #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+ {
+ if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+ {
+ BaseType_t xIndex;
+
+ 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
+
+ /* Send! */
+ xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
+
+ if( xReleaseAfterSend == pdFALSE )
+ {
+ /* Swap-back some fields, as pxBuffer probably points to a socket field
+ containing the packet header. */
+ vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);
+ pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;
+ memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
+ }
+ else
+ {
+ /* Nothing to do: the buffer has been passed to DMA and will be released after use */
+ }
+ } /* if( pxNetworkBuffer != NULL ) */
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * The SYN event is very important: the sequence numbers, which have a kind of
+ * random starting value, are being synchronised. The sliding window manager
+ * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment
+ * Size (MSS) in use.
+ */
+static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket )
+{
+ if( xTCPWindowLoggingLevel )
+ FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n",
+ pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,
+ pxSocket->u.xTCP.uxLittleSpace ,
+ pxSocket->u.xTCP.uxEnoughSpace,
+ pxSocket->u.xTCP.uxRxStreamSize ) );
+ vTCPWindowCreate(
+ &pxSocket->u.xTCP.xTCPWindow,
+ ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize,
+ ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize,
+ pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,
+ pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,
+ ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Connecting sockets have a special state: eCONNECT_SYN. In this phase,
+ * the Ethernet address of the target will be found using ARP. In case the
+ * target IP address is not within the netmask, the hardware address of the
+ * gateway will be used.
+ */
+static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket )
+{
+TCPPacket_t *pxTCPPacket;
+IPHeader_t *pxIPHeader;
+eARPLookupResult_t eReturned;
+uint32_t ulRemoteIP;
+MACAddress_t xEthAddress;
+BaseType_t xReturn = pdTRUE;
+
+ #if( ipconfigHAS_PRINTF != 0 )
+ {
+ /* Only necessary for nicer logging. */
+ memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) );
+ }
+ #endif /* ipconfigHAS_PRINTF != 0 */
+
+ ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
+
+ /* Determine the ARP cache status for the requested IP address. */
+ eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );
+
+ switch( eReturned )
+ {
+ case eARPCacheHit: /* An ARP table lookup found a valid entry. */
+ break; /* We can now prepare the SYN packet. */
+ case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */
+ case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */
+ default:
+ /* Count the number of times it couldn't find the ARP address. */
+ pxSocket->u.xTCP.ucRepCount++;
+
+ FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",
+ pxSocket->u.xTCP.ulRemoteIP,
+ FreeRTOS_htonl( ulRemoteIP ),
+ eReturned,
+ xEthAddress.ucBytes[ 0 ],
+ xEthAddress.ucBytes[ 1 ],
+ xEthAddress.ucBytes[ 2 ],
+ xEthAddress.ucBytes[ 3 ],
+ xEthAddress.ucBytes[ 4 ],
+ xEthAddress.ucBytes[ 5 ] ) );
+
+ /* And issue a (new) ARP request */
+ FreeRTOS_OutputARPRequest( ulRemoteIP );
+
+ xReturn = pdFALSE;
+ break;
+ }
+
+ if( xReturn != pdFALSE )
+ {
+ /* The MAC-address of the peer (or gateway) has been found,
+ now prepare the initial TCP packet and some fields in the socket. */
+ pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;
+ pxIPHeader = &pxTCPPacket->xIPHeader;
+
+ /* Reset the retry counter to zero... */
+ pxSocket->u.xTCP.ucRepCount = 0u;
+
+ /* ...and remember that the connect/SYN data are prepared. */
+ pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;
+
+ /* Now that the Ethernet address is known, the initial packet can be
+ prepared. */
+ memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
+
+ /* Write the Ethernet address in Source, because it will be swapped by
+ prvTCPReturnPacket(). */
+ memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) );
+
+ /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */
+ pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;
+
+ pxIPHeader->ucVersionHeaderLength = 0x45u;
+ pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );
+ pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;
+
+ pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;
+
+ /* Addresses and ports will be stored swapped because prvTCPReturnPacket
+ will swap them back while replying. */
+ pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
+ pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
+
+ pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
+ pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );
+
+ /* We are actively connecting, so the peer's Initial Sequence Number (ISN)
+ isn't known yet. */
+ pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul;
+
+ /* Start with ISN (Initial Sequence Number). */
+ pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber;
+
+ /* And increment it with 268 for the next new connection, which is
+ recommended value. */
+ ulNextInitialSequenceNumber += 0x102UL;
+
+ /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in
+ the high nibble of the TCP offset field. */
+ pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u;
+
+ /* Only set the SYN flag. */
+ pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN;
+
+ /* Set the values of usInitMSS / usCurMSS for this socket. */
+ prvSocketSetMSS( pxSocket );
+
+ /* For now this is also the advertised window size. */
+ pxSocket->u.xTCP.ulRxCurWinSize = pxSocket->u.xTCP.usInitMSS;
+
+ /* The initial sequence numbers at our side are known. Later
+ vTCPWindowInit() will be called to fill in the peer's sequence numbers, but
+ first wait for a SYN+ACK reply. */
+ prvTCPCreateWindow( pxSocket );
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+/* For logging and debugging: make a string showing the TCP flags
+*/
+#if( ipconfigHAS_DEBUG_PRINTF != 0 )
+
+ static const char *prvTCPFlagMeaning( UBaseType_t xFlags)
+ {
+ static char retString[10];
+ snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c",
+ ( xFlags & ipTCP_FLAG_FIN ) ? 'F' : '.', /* 0x0001: No more data from sender */
+ ( xFlags & ipTCP_FLAG_SYN ) ? 'S' : '.', /* 0x0002: Synchronize sequence numbers */
+ ( xFlags & ipTCP_FLAG_RST ) ? 'R' : '.', /* 0x0004: Reset the connection */
+ ( xFlags & ipTCP_FLAG_PSH ) ? 'P' : '.', /* 0x0008: Push function: please push buffered data to the recv application */
+ ( xFlags & ipTCP_FLAG_ACK ) ? 'A' : '.', /* 0x0010: Acknowledgment field is significant */
+ ( xFlags & ipTCP_FLAG_URG ) ? 'U' : '.', /* 0x0020: Urgent pointer field is significant */
+ ( xFlags & ipTCP_FLAG_ECN ) ? 'E' : '.', /* 0x0040: ECN-Echo */
+ ( xFlags & ipTCP_FLAG_CWR ) ? 'C' : '.', /* 0x0080: Congestion Window Reduced */
+ ( xFlags & ipTCP_FLAG_NS ) ? 'N' : '.'); /* 0x0100: ECN-nonce concealment protection */
+ return retString;
+ }
+ /*-----------------------------------------------------------*/
+
+#endif /* ipconfigHAS_DEBUG_PRINTF */
+
+/*
+ * Parse the TCP option(s) received, if present. It has already been verified
+ * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header
+ * is longer than the usual 20 (5 x 4) bytes.
+ */
+static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+TCPPacket_t * pxTCPPacket;
+TCPHeader_t * pxTCPHeader;
+const unsigned char *pucPtr;
+const unsigned char *pucLast;
+TCPWindow_t *pxTCPWindow;
+UBaseType_t uxNewMSS;
+
+ pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+ pxTCPHeader = &pxTCPPacket->xTCPHeader;
+
+ /* A character pointer to iterate through the option data */
+ pucPtr = pxTCPHeader->ucOptdata;
+ pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2);
+ pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+
+ /* The comparison with pucLast is only necessary in case the option data are
+ corrupted, we don't like to run into invalid memory and crash. */
+ while( pucPtr < pucLast )
+ {
+ if( pucPtr[ 0 ] == TCP_OPT_END )
+ {
+ /* End of options. */
+ return;
+ }
+ if( pucPtr[ 0 ] == TCP_OPT_NOOP)
+ {
+ pucPtr++;
+
+ /* NOP option, inserted to make the length a multiple of 4. */
+ }
+#if( ipconfigUSE_TCP_WIN != 0 )
+ else if( ( pucPtr[ 0 ] == TCP_OPT_WSOPT ) && ( pucPtr[ 1 ] == TCP_OPT_WSOPT_LEN ) )
+ {
+ pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ];
+ pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;
+ pucPtr += TCP_OPT_WSOPT_LEN;
+ }
+#endif /* ipconfigUSE_TCP_WIN */
+ else if( ( pucPtr[ 0 ] == TCP_OPT_MSS ) && ( pucPtr[ 1 ] == TCP_OPT_MSS_LEN ) )
+ {
+ /* An MSS option with the correct option length. FreeRTOS_htons()
+ is not needed here because usChar2u16() already returns a host
+ endian number. */
+ uxNewMSS = usChar2u16( pucPtr + 2 );
+
+ if( pxSocket->u.xTCP.usInitMSS != uxNewMSS )
+ {
+ FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) );
+ }
+
+ if( pxSocket->u.xTCP.usInitMSS > uxNewMSS )
+ {
+ /* our MSS was bigger than the MSS of the other party: adapt it. */
+ pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;
+ if( ( pxTCPWindow != NULL ) && ( pxSocket->u.xTCP.usCurMSS > uxNewMSS ) )
+ {
+ /* The peer advertises a smaller MSS than this socket was
+ using. Use that as well. */
+ FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", pxSocket->u.xTCP.usCurMSS, uxNewMSS ) );
+ pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
+ }
+ pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );
+ pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS;
+ pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS;
+ pxSocket->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;
+ pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;
+ }
+
+ #if( ipconfigUSE_TCP_WIN != 1 )
+ /* Without scaled windows, MSS is the only interesting option. */
+ break;
+ #else
+ /* Or else we continue to check another option: selective ACK. */
+ pucPtr += TCP_OPT_MSS_LEN;
+ #endif /* ipconfigUSE_TCP_WIN != 1 */
+ }
+ else
+ {
+ /* All other options have a length field, so that we easily
+ can skip past them. */
+ int len = ( int )pucPtr[ 1 ];
+ if( len == 0 )
+ {
+ /* If the length field is zero, the options are malformed
+ and we don't process them further. */
+ break;
+ }
+
+ #if( ipconfigUSE_TCP_WIN == 1 )
+ {
+ /* Selective ACK: the peer has received a packet but it is missing earlier
+ packets. At least this packet does not need retransmission anymore
+ ulTCPWindowTxSack( ) takes care of this administration. */
+ if( pucPtr[0] == TCP_OPT_SACK_A )
+ {
+ len -= 2;
+ pucPtr += 2;
+
+ while( len >= 8 )
+ {
+ uint32_t ulFirst = ulChar2u32( pucPtr );
+ uint32_t ulLast = ulChar2u32( pucPtr + 4 );
+ uint32_t ulCount = ulTCPWindowTxSack( &pxSocket->u.xTCP.xTCPWindow, ulFirst, ulLast );
+ /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked
+ starting from the head position.
+ Advance the tail pointer in txStream. */
+ if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0 ) )
+ {
+ /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */
+ uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );
+ pxSocket->xEventBits |= eSOCKET_SEND;
+
+ #if ipconfigSUPPORT_SELECT_FUNCTION == 1
+ {
+ if( pxSocket->xSelectBits & eSELECT_WRITE )
+ {
+ /* The field 'xEventBits' is used to store regular socket events (at most 8),
+ as well as 'select events', which will be left-shifted */
+ pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
+ }
+ }
+ #endif
+
+ /* In case the socket owner has installed an OnSent handler,
+ call it now. */
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ {
+ if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
+ {
+ pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
+ }
+ }
+ #endif /* ipconfigUSE_CALLBACKS == 1 */
+ }
+ pucPtr += 8;
+ len -= 8;
+ }
+ /* len should be 0 by now. */
+ }
+ #if ipconfigUSE_TCP_TIMESTAMPS == 1
+ else if( pucPtr[0] == TCP_OPT_TIMESTAMP )
+ {
+ len -= 2; /* Skip option and length byte. */
+ pucPtr += 2;
+ pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps = pdTRUE_UNSIGNED;
+ pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = ulChar2u32( pucPtr );
+ pxSocket->u.xTCP.xTCPWindow.tx.ulTimeStamp = ulChar2u32( pucPtr + 4 );
+ }
+ #endif /* ipconfigUSE_TCP_TIMESTAMPS == 1 */
+ }
+ #endif /* ipconfigUSE_TCP_WIN == 1 */
+
+ pucPtr += len;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN != 0 )
+
+ static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket )
+ {
+ size_t uxWinSize;
+ uint8_t ucFactor;
+
+ /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */
+ uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS;
+ ucFactor = 0u;
+ while( uxWinSize > 0xfffful )
+ {
+ /* Divide by two and increase the binary factor by 1. */
+ uxWinSize >>= 1;
+ ucFactor++;
+ }
+
+ FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n",
+ pxSocket->u.xTCP.uxRxWinSize,
+ pxSocket->u.xTCP.usInitMSS,
+ ucFactor ) );
+
+ return ucFactor;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+/*
+ * When opening a TCP connection, while SYN's are being sent, the parties may
+ * communicate what MSS (Maximum Segment Size) they intend to use. MSS is the
+ * nett size of the payload, always smaller than MTU.
+*/
+static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket )
+{
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+uint16_t usMSS = pxSocket->u.xTCP.usInitMSS;
+UBaseType_t uxOptionsLength;
+
+ /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */
+
+ pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS;
+ pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN;
+ pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );
+ pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu );
+
+ #if( ipconfigUSE_TCP_WIN != 0 )
+ {
+ pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );
+
+ pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP;
+ pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT );
+ pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN );
+ pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;
+ uxOptionsLength = 8u;
+ }
+ #else
+ {
+ uxOptionsLength = 4u;
+ }
+ #endif
+
+ #if( ipconfigUSE_TCP_WIN == 0 )
+ {
+ return uxOptionsLength;
+ }
+ #else
+ {
+ #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
+ if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )
+ {
+ uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, &pxTCPPacket->xTCPHeader );
+ pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
+ pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = 2u;
+ uxOptionsLength += 2u;
+ }
+ else
+ #endif
+ {
+ pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP;
+ pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP;
+ pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */
+ pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2; /* 2: length of this option. */
+ uxOptionsLength += 4u;
+ }
+ return uxOptionsLength; /* bytes, not words. */
+ }
+ #endif /* ipconfigUSE_TCP_WIN == 0 */
+}
+
+/*
+ * For anti-hanging protection and TCP keep-alive messages. Called in two
+ * places: after receiving a packet and after a state change. The socket's
+ * alive timer may be reset.
+ */
+static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket )
+{
+ #if( ipconfigTCP_HANG_PROTECTION == 1 )
+ {
+ pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( );
+ }
+ #endif
+
+ #if( ipconfigTCP_KEEP_ALIVE == 1 )
+ {
+ pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;
+ pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;
+ pxSocket->u.xTCP.ucKeepRepCount = 0u;
+ pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
+ }
+ #endif
+
+ ( void ) pxSocket;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Changing to a new state. Centralised here to do specific actions such as
+ * resetting the alive timer, calling the user's OnConnect handler to notify
+ * that a socket has got (dis)connected, and setting bit to unblock a call to
+ * FreeRTOS_select()
+ */
+void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState )
+{
+FreeRTOS_Socket_t *xParent = NULL;
+BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState ); /* Was it connected ? */
+BaseType_t bAfter = ( BaseType_t ) NOW_CONNECTED( eTCPState ); /* Is it connected now ? */
+#if( ipconfigHAS_DEBUG_PRINTF != 0 )
+ BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState;
+#endif
+#if( ipconfigUSE_CALLBACKS == 1 )
+ FreeRTOS_Socket_t *xConnected = NULL;
+#endif
+
+ /* Has the connected status changed? */
+ if( bBefore != bAfter )
+ {
+ /* Is the socket connected now ? */
+ if( bAfter != pdFALSE )
+ {
+ /* if bPassQueued is true, this socket is an orphan until it gets connected. */
+ if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
+ {
+ /* Now that it is connected, find it's parent. */
+ if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
+ {
+ xParent = pxSocket;
+ }
+ else
+ {
+ xParent = pxSocket->u.xTCP.pxPeerSocket;
+ configASSERT( xParent != NULL );
+ }
+ if( xParent != NULL )
+ {
+ if( xParent->u.xTCP.pxPeerSocket == NULL )
+ {
+ xParent->u.xTCP.pxPeerSocket = pxSocket;
+ }
+
+ xParent->xEventBits |= eSOCKET_ACCEPT;
+
+ #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+ {
+ /* Library support FreeRTOS_select(). Receiving a new
+ connection is being translated as a READ event. */
+ if( ( xParent->xSelectBits & eSELECT_READ ) != 0 )
+ {
+ xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );
+ }
+ }
+ #endif
+
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ {
+ if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) &&
+ ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )
+ {
+ /* The listening socket does not become connected itself, in stead
+ a child socket is created.
+ Postpone a call the OnConnect event until the end of this function. */
+ xConnected = xParent;
+ }
+ }
+ #endif
+ }
+
+ /* Don't need to access the parent socket anymore, so the
+ reference 'pxPeerSocket' may be cleared. */
+ pxSocket->u.xTCP.pxPeerSocket = NULL;
+ pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;
+
+ /* When true, this socket may be returned in a call to accept(). */
+ pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
+ }
+ else
+ {
+ pxSocket->xEventBits |= eSOCKET_CONNECT;
+
+ #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+ {
+ if( pxSocket->xSelectBits & eSELECT_WRITE )
+ {
+ pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
+ }
+ }
+ #endif
+ }
+ }
+ else /* bAfter == pdFALSE, connection is closed. */
+ {
+ /* Notify/wake-up the socket-owner by setting a semaphore. */
+ pxSocket->xEventBits |= eSOCKET_CLOSED;
+
+ #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+ {
+ if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )
+ {
+ pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT );
+ }
+ }
+ #endif
+ }
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ {
+ if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) )
+ {
+ /* The 'connected' state has changed, call the user handler. */
+ xConnected = pxSocket;
+ }
+ }
+ #endif /* ipconfigUSE_CALLBACKS */
+
+ if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE )
+ {
+ /* Now the socket isn't in an active state anymore so it
+ won't need further attention of the IP-task.
+ Setting time-out to zero means that the socket won't get checked during
+ timer events. */
+ pxSocket->u.xTCP.usTimeout = 0u;
+ }
+ }
+ else
+ {
+ if( eTCPState == eCLOSED )
+ {
+ /* Socket goes to status eCLOSED because of a RST.
+ When nobody owns the socket yet, delete it. */
+ if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
+ ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
+ {
+ FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );
+ if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
+ {
+ FreeRTOS_closesocket( pxSocket );
+ }
+ }
+ }
+ }
+
+ /* Fill in the new state. */
+ pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState;
+
+ /* Touch the alive timers because moving to another state. */
+ prvTCPTouchSocket( pxSocket );
+
+ #if( ipconfigHAS_DEBUG_PRINTF == 1 )
+ {
+ if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
+ FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.ulRemoteIP,
+ pxSocket->u.xTCP.usRemotePort,
+ FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),
+ FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );
+ }
+ #endif /* ipconfigHAS_DEBUG_PRINTF */
+
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ {
+ if( xConnected != NULL )
+ {
+ /* The 'connected' state has changed, call the OnConnect handler of the parent. */
+ xConnected->u.xTCP.pxHandleConnected( ( Socket_t * ) xConnected, bAfter );
+ }
+ }
+ #endif
+ if( xParent != NULL )
+ {
+ vSocketWakeUpUser( xParent );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,
+ int32_t lDataLen, UBaseType_t uxOptionsLength )
+{
+NetworkBufferDescriptor_t *pxReturn;
+int32_t lNeeded;
+BaseType_t xResize;
+
+ if( xBufferAllocFixedSize != pdFALSE )
+ {
+ /* Network buffers are created with a fixed size and can hold the largest
+ MTU. */
+ lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE;
+ /* and therefore, the buffer won't be too small.
+ Only ask for a new network buffer in case none was supplied. */
+ xResize = ( pxNetworkBuffer == NULL );
+ }
+ else
+ {
+ /* Network buffers are created with a variable size. See if it must
+ grow. */
+ lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ),
+ ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen );
+ /* In case we were called from a TCP timer event, a buffer must be
+ created. Otherwise, test 'xDataLength' of the provided buffer. */
+ if( ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded ) )
+ {
+ xResize = pdTRUE;
+ }
+ else
+ {
+ xResize = pdFALSE;
+ }
+ }
+
+ if( xResize != pdFALSE )
+ {
+ /* The caller didn't provide a network buffer or the provided buffer is
+ too small. As we must send-out a data packet, a buffer will be created
+ here. */
+ pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u );
+
+ if( pxReturn != NULL )
+ {
+ /* Copy the existing data to the new created buffer. */
+ if( pxNetworkBuffer )
+ {
+ /* Either from the previous buffer... */
+ memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
+
+ /* ...and release it. */
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ }
+ else
+ {
+ /* Or from the socket field 'xTCP.xPacket'. */
+ memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
+ }
+ }
+ }
+ else
+ {
+ /* xResize is false, the network buffer provided was big enough. */
+ pxReturn = pxNetworkBuffer;
+
+ /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the
+ xDataLength member must get the correct length too! */
+ pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;
+ }
+
+ return pxReturn;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Prepare an outgoing message, in case anything has to be sent.
+ */
+static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )
+{
+int32_t lDataLen;
+uint8_t *pucEthernetBuffer, *pucSendData;
+TCPPacket_t *pxTCPPacket;
+size_t uxOffset;
+uint32_t ulDataGot, ulDistance;
+TCPWindow_t *pxTCPWindow;
+NetworkBufferDescriptor_t *pxNewBuffer;
+int32_t lStreamPos;
+
+ if( ( *ppxNetworkBuffer ) != NULL )
+ {
+ /* A network buffer descriptor was already supplied */
+ pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;
+ }
+ else
+ {
+ /* For now let it point to the last packet header */
+ pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
+ }
+
+ pxTCPPacket = ( TCPPacket_t * ) pucEthernetBuffer;
+ pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
+ lDataLen = 0;
+ lStreamPos = 0;
+ pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK;
+
+ if( pxSocket->u.xTCP.txStream != NULL )
+ {
+ /* ulTCPWindowTxGet will return the amount of data which may be sent
+ along with the position in the txStream.
+ Why check for MSS > 1 ?
+ Because some TCP-stacks (like uIP) use it for flow-control. */
+ if( pxSocket->u.xTCP.usCurMSS > 1u )
+ {
+ lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );
+ }
+
+ if( lDataLen > 0 )
+ {
+ /* Check if the current network buffer is big enough, if not,
+ resize it. */
+ pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );
+
+ if( pxNewBuffer != NULL )
+ {
+ *ppxNetworkBuffer = pxNewBuffer;
+ pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;
+ pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
+
+ pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
+
+ /* Translate the position in txStream to an offset from the tail
+ marker. */
+ uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );
+
+ /* Here data is copied from the txStream in 'peek' mode. Only
+ when the packets are acked, the tail marker will be updated. */
+ ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );
+
+ #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+ {
+ if( ulDataGot != ( uint32_t ) lDataLen )
+ {
+ FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n",
+ lStreamPos, uxOffset, ulDataGot, lDataLen ) );
+ }
+ }
+ #endif
+
+ /* If the owner of the socket requests a closure, add the FIN
+ flag to the last packet. */
+ if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) )
+ {
+ ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );
+
+ if( ulDistance == ulDataGot )
+ {
+ #if (ipconfigHAS_DEBUG_PRINTF == 1)
+ {
+ /* the order of volatile accesses is undefined
+ so such workaround */
+ size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;
+ size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;
+ size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;
+
+ FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,
+ uxTail, uxMid, uxHead ) );
+ }
+ #endif
+ /* Although the socket sends a FIN, it will stay in
+ ESTABLISHED until all current data has been received or
+ delivered. */
+ pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
+ pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;
+ pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
+ }
+ }
+ }
+ else
+ {
+ lDataLen = -1;
+ }
+ }
+ }
+
+ if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) )
+ {
+ /* See if the socket owner wants to shutdown this connection. */
+ if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&
+ ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )
+ {
+ pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;
+ pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;
+ pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
+ pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
+ pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
+ vTCPStateChange( pxSocket, eFIN_WAIT_1 );
+ }
+
+ #if( ipconfigTCP_KEEP_ALIVE != 0 )
+ {
+ if( pxSocket->u.xTCP.ucKeepRepCount > 3u )
+ {
+ FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",
+ pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
+ pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
+ vTCPStateChange( pxSocket, eCLOSE_WAIT );
+ lDataLen = -1;
+ }
+ if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )
+ {
+ /* If there is no data to be sent, and no window-update message,
+ we might want to send a keep-alive message. */
+ TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime;
+ TickType_t xMax;
+ xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ );
+ if( pxSocket->u.xTCP.ucKeepRepCount )
+ {
+ xMax = ( 3u * configTICK_RATE_HZ );
+ }
+ if( xAge > xMax )
+ {
+ pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );
+ if( xTCPWindowLoggingLevel )
+ FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",
+ pxSocket->u.xTCP.ulRemoteIP,
+ pxSocket->u.xTCP.usRemotePort,
+ pxSocket->u.xTCP.ucKeepRepCount ) );
+ pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;
+ pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) );
+ pxSocket->u.xTCP.ucKeepRepCount++;
+ }
+ }
+ }
+ #endif /* ipconfigTCP_KEEP_ALIVE */
+ }
+
+ /* Anything to send, a change of the advertised window size, or maybe send a
+ keep-alive message? */
+ if( ( lDataLen > 0 ) ||
+ ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||
+ ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )
+ {
+ pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );
+ pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+
+ pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;
+
+ if( lDataLen != 0l )
+ {
+ pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;
+ }
+
+ #if ipconfigUSE_TCP_TIMESTAMPS == 1
+ {
+ if( uxOptionsLength == 0u )
+ {
+ if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )
+ {
+ TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
+ uxOptionsLength = prvTCPSetTimeStamp( 0, pxSocket, &pxTCPPacket->xTCPHeader );
+ }
+ }
+ }
+ #endif
+
+ lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+ }
+
+ return lDataLen;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Calculate after how much time this socket needs to be checked again.
+ */
+static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket )
+{
+TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
+
+ if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
+ {
+ /* The socket is actively connecting to a peer. */
+ if( pxSocket->u.xTCP.bits.bConnPrepared )
+ {
+ /* Ethernet address has been found, use progressive timeout for
+ active connect(). */
+ if( pxSocket->u.xTCP.ucRepCount < 3u )
+ {
+ ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) );
+ }
+ else
+ {
+ ulDelayMs = 11000UL;
+ }
+ }
+ else
+ {
+ /* Still in the ARP phase: check every half second. */
+ ulDelayMs = 500UL;
+ }
+
+ FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n",
+ pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,
+ pxSocket->u.xTCP.ucRepCount, ulDelayMs ) );
+ pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
+ }
+ else if( pxSocket->u.xTCP.usTimeout == 0u )
+ {
+ /* Let the sliding window mechanism decide what time-out is appropriate. */
+ BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );
+ if( ulDelayMs == 0u )
+ {
+ if( xResult != ( BaseType_t )0 )
+ {
+ ulDelayMs = 1UL;
+ }
+ else
+ {
+ ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;
+ }
+ }
+ else
+ {
+ /* ulDelayMs contains the time to wait before a re-transmission. */
+ }
+ pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );
+ }
+ else
+ {
+ /* field '.usTimeout' has already been set (by the
+ keep-alive/delayed-ACK mechanism). */
+ }
+
+ /* Return the number of clock ticks before the timer expires. */
+ return ( TickType_t ) pxSocket->u.xTCP.usTimeout;
+}
+/*-----------------------------------------------------------*/
+
+static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket )
+{
+int32_t lCount, lLength;
+
+ /* A txStream has been created already, see if the socket has new data for
+ the sliding window.
+
+ uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It
+ contains new Tx data which has not been passed to the sliding window yet.
+ The oldest data not-yet-confirmed can be found at rxTail. */
+ lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );
+
+ if( lLength > 0 )
+ {
+ /* All data between txMid and rxHead will now be passed to the sliding
+ window manager, so it can start transmitting them.
+
+ Hand over the new data to the sliding window handler. It will be
+ split-up in chunks of 1460 bytes each (or less, depending on
+ ipconfigTCP_MSS). */
+ lCount = lTCPWindowTxAdd( &pxSocket->u.xTCP.xTCPWindow,
+ ( uint32_t ) lLength,
+ ( int32_t ) pxSocket->u.xTCP.txStream->uxMid,
+ ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );
+
+ /* Move the rxMid pointer forward up to rxHead. */
+ if( lCount > 0 )
+ {
+ vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvTCPHandleFin() will be called to handle socket closure
+ * The Closure starts when either a FIN has been received and accepted,
+ * Or when the socket has sent a FIN flag to the peer
+ * Before being called, it has been checked that both reception and transmission
+ * are complete.
+ */
+static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+BaseType_t xSendLength = 0;
+uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );
+
+ if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u )
+ {
+ pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u;
+ }
+ if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
+ {
+ /* We haven't yet replied with a FIN, do so now. */
+ pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
+ pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
+ }
+ else
+ {
+ /* We did send a FIN already, see if it's ACK'd. */
+ if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u )
+ {
+ pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;
+ }
+ }
+
+ if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )
+ {
+ pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
+ pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN;
+
+ /* And wait for the final ACK. */
+ vTCPStateChange( pxSocket, eLAST_ACK );
+ }
+ else
+ {
+ /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */
+ pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u;
+ if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )
+ {
+ /* We have sent out a FIN but the peer hasn't replied with a FIN
+ yet. Do nothing for the moment. */
+ pxTCPHeader->ucTCPFlags = 0u;
+ }
+ else
+ {
+ if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )
+ {
+ /* This is the third of the three-way hand shake: the last
+ ACK. */
+ pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
+ }
+ else
+ {
+ /* The other party started the closure, so we just wait for the
+ last ACK. */
+ pxTCPHeader->ucTCPFlags = 0u;
+ }
+
+ /* And wait for the user to close this socket. */
+ vTCPStateChange( pxSocket, eCLOSE_WAIT );
+ }
+ }
+
+ pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
+
+ if( pxTCPHeader->ucTCPFlags != 0u )
+ {
+ xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );
+ }
+
+ pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );
+
+ if( xTCPWindowLoggingLevel != 0 )
+ {
+ FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n",
+ ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber,
+ pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+ pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+ pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+ pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
+ }
+
+ return xSendLength;
+}
+/*-----------------------------------------------------------*/
+
+#if ipconfigUSE_TCP_TIMESTAMPS == 1
+
+ static UBaseType_t prvTCPSetTimeStamp( BaseType_t lOffset, FreeRTOS_Socket_t *pxSocket, TCPHeader_t *pxTCPHeader )
+ {
+ uint32_t ulTimes[2];
+ uint8_t *ucOptdata = &( pxTCPHeader->ucOptdata[ lOffset ] );
+
+ ulTimes[0] = ( xTaskGetTickCount ( ) * 1000u ) / configTICK_RATE_HZ;
+ ulTimes[0] = FreeRTOS_htonl( ulTimes[0] );
+ ulTimes[1] = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp );
+ ucOptdata[0] = ( uint8_t ) TCP_OPT_TIMESTAMP;
+ ucOptdata[1] = ( uint8_t ) TCP_OPT_TIMESTAMP_LEN;
+ memcpy( &(ucOptdata[2] ), ulTimes, 8u );
+ ucOptdata[10] = ( uint8_t ) TCP_OPT_NOOP;
+ ucOptdata[11] = ( uint8_t ) TCP_OPT_NOOP;
+ /* Do not return the same timestamps 2 times. */
+ pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = 0ul;
+ return 12u;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+/*
+ * prvCheckRxData(): called from prvTCPHandleState()
+ *
+ * The first thing that will be done is find the TCP payload data
+ * and check the length of this data.
+ */
+static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
+int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;
+
+ /* Determine the length and the offset of the user-data sent to this
+ node.
+
+ The size of the TCP header is given in a multiple of 4-byte words (single
+ byte, needs no ntoh() translation). A shift-right 2: is the same as
+ (offset >> 4) * 4. */
+ lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );
+
+ /* Let pucRecvData point to the first byte received. */
+ *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength;
+
+ /* Calculate lReceiveLength - the length of the TCP data received. This is
+ equal to the total packet length minus:
+ ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/
+ lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;
+ lLength = ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength );
+
+ if( lReceiveLength > lLength )
+ {
+ /* More bytes were received than the reported length, often because of
+ padding bytes at the end. */
+ lReceiveLength = lLength;
+ }
+
+ /* Subtract the size of the TCP and IP headers and the actual data size is
+ known. */
+ if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) )
+ {
+ lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER );
+ }
+ else
+ {
+ lReceiveLength = 0;
+ }
+
+ /* Urgent Pointer:
+ This field communicates the current value of the urgent pointer as a
+ positive offset from the sequence number in this segment. The urgent
+ pointer points to the sequence number of the octet following the urgent
+ data. This field is only be interpreted in segments with the URG control
+ bit set. */
+ if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u )
+ {
+ /* Although we ignore the urgent data, we have to skip it. */
+ lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );
+ *ppucRecvData += lUrgentLength;
+ lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );
+ }
+
+ return ( BaseType_t ) lReceiveLength;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvStoreRxData(): called from prvTCPHandleState()
+ *
+ * The second thing is to do is check if the payload data may be accepted
+ * If so, they will be added to the reception queue.
+ */
+static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,
+ NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+uint32_t ulSequenceNumber, ulSpace;
+int32_t lOffset, lStored;
+BaseType_t xResult = 0;
+
+ ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
+
+ if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) )
+ {
+ /* See if way may accept the data contents and forward it to the socket
+ owner.
+
+ If it can't be "accept"ed it may have to be stored and send a selective
+ ack (SACK) option to confirm it. In that case, xTCPWindowRxStore() will be
+ called later to store an out-of-order packet (in case lOffset is
+ negative). */
+ if ( pxSocket->u.xTCP.rxStream )
+ {
+ ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream );
+ }
+ else
+ {
+ ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize;
+ }
+
+ lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace );
+
+ if( lOffset >= 0 )
+ {
+ /* New data has arrived and may be made available to the user. See
+ if the head marker in rxStream may be advanced, only if lOffset == 0.
+ In case the low-water mark is reached, bLowWater will be set
+ "low-water" here stands for "little space". */
+ lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength );
+
+ if( lStored != ( int32_t ) ulReceiveLength )
+ {
+ FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) );
+
+ /* Received data could not be stored. The socket's flag
+ bMallocError has been set. The socket now has the status
+ eCLOSE_WAIT and a RST packet will be sent back. */
+ prvTCPSendReset( pxNetworkBuffer );
+ xResult = -1;
+ }
+ }
+
+ /* After a missing packet has come in, higher packets may be passed to
+ the user. */
+ #if( ipconfigUSE_TCP_WIN == 1 )
+ {
+ /* Now lTCPAddRxdata() will move the rxHead pointer forward
+ so data becomes available to the user immediately
+ In case the low-water mark is reached, bLowWater will be set. */
+ if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) )
+ {
+ lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength );
+ pxTCPWindow->ulUserDataLength = 0;
+ }
+ }
+ #endif /* ipconfigUSE_TCP_WIN */
+ }
+ else
+ {
+ pxTCPWindow->ucOptionLength = 0u;
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+/* Set the TCP options (if any) for the outgoing packet. */
+static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;
+
+ #if( ipconfigUSE_TCP_WIN == 1 )
+ if( uxOptionsLength != 0u )
+ {
+ /* TCP options must be sent because a packet which is out-of-order
+ was received. */
+ if( xTCPWindowLoggingLevel >= 0 )
+ FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.usRemotePort,
+ uxOptionsLength,
+ FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,
+ FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) );
+ memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength );
+
+ /* The header length divided by 4, goes into the higher nibble,
+ effectively a shift-left 2. */
+ pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+ }
+ else
+ #endif /* ipconfigUSE_TCP_WIN */
+ if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )
+ {
+ /* TCP options must be sent because the MSS has changed. */
+ pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;
+ if( xTCPWindowLoggingLevel >= 0 )
+ {
+ FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) );
+ }
+
+ pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS;
+ pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN;
+ pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 );
+ pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu );
+ uxOptionsLength = 4u;
+ pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+ }
+
+ #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
+ {
+ if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )
+ {
+ uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, pxTCPHeader );
+ }
+ }
+ #endif /* ipconfigUSE_TCP_TIMESTAMPS == 1 */
+
+ return uxOptionsLength;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvHandleSynReceived(): called from prvTCPHandleState()
+ *
+ * Called from the states: eSYN_RECEIVED and eCONNECT_SYN
+ * If the flags received are correct, the socket will move to eESTABLISHED.
+ */
+static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+ uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
+uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );
+BaseType_t xSendLength = 0;
+
+ /* Either expect a ACK or a SYN+ACK. */
+ uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK;
+ if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
+ {
+ usExpect |= ( uint16_t ) ipTCP_FLAG_SYN;
+ }
+
+ if( ( ucTCPFlags & 0x17u ) != usExpect )
+ {
+ /* eSYN_RECEIVED: flags 0010 expected, not 0002. */
+ /* eSYN_RECEIVED: flags ACK expected, not SYN. */
+ FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",
+ pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",
+ usExpect, ucTCPFlags ) );
+ vTCPStateChange( pxSocket, eCLOSE_WAIT );
+ pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;
+ xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+ pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+ }
+ else
+ {
+ pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;
+ pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;
+
+ if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )
+ {
+ TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
+
+ /* Clear the SYN flag in lastPacket. */
+ pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK;
+
+ /* This socket was the one connecting actively so now perofmr the
+ synchronisation. */
+ vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,
+ ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );
+ pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
+ pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */
+ pxTCPWindow->ulNextTxSequenceNumber++;
+ }
+ else if( ulReceiveLength == 0u )
+ {
+ pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
+ }
+
+ /* The SYN+ACK has been confirmed, increase the next sequence number by
+ 1. */
+ pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u;
+
+ #if( ipconfigUSE_TCP_WIN == 1 )
+ {
+ FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n",
+ pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.ulRemoteIP,
+ pxSocket->u.xTCP.usRemotePort,
+ ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );
+ }
+ #endif /* ipconfigUSE_TCP_WIN */
+
+ if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) )
+ {
+ pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
+ xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+ pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+ }
+ #if( ipconfigUSE_TCP_WIN != 0 )
+ {
+ if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )
+ {
+ /* The other party did not send a scaling factor.
+ A shifting factor in this side must be canceled. */
+ pxSocket->u.xTCP.ucMyWinScaleFactor = 0;
+ pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;
+ }
+ }
+ #endif /* ipconfigUSE_TCP_WIN */
+ /* This was the third step of connecting: SYN, SYN+ACK, ACK so now the
+ connection is established. */
+ vTCPStateChange( pxSocket, eESTABLISHED );
+ }
+
+ return xSendLength;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvHandleEstablished(): called from prvTCPHandleState()
+ *
+ * Called if the status is eESTABLISHED. Data reception has been handled
+ * earlier. Here the ACK's from peer will be checked, and if a FIN is received,
+ * the code will check if it may be accepted, i.e. if all expected data has been
+ * completely received.
+ */
+static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+ uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
+uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount;
+BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;
+int32_t lDistance, lSendResult;
+
+ /* Remember the window size the peer is advertising. */
+ pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow );
+ #if( ipconfigUSE_TCP_WIN != 0 )
+ {
+ pxSocket->u.xTCP.ulWindowSize =
+ ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
+ }
+ #endif
+
+ if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u )
+ {
+ ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) );
+
+ /* ulTCPWindowTxAck() returns the number of bytes which have been acked,
+ starting at 'tx.ulCurrentSequenceNumber'. Advance the tail pointer in
+ txStream. */
+ if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) )
+ {
+ /* Just advancing the tail index, 'ulCount' bytes have been
+ confirmed, and because there is new space in the txStream, the
+ user/owner should be woken up. */
+ /* _HT_ : only in case the socket's waiting? */
+ if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u )
+ {
+ pxSocket->xEventBits |= eSOCKET_SEND;
+
+ #if ipconfigSUPPORT_SELECT_FUNCTION == 1
+ {
+ if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )
+ {
+ pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );
+ }
+ }
+ #endif
+ /* In case the socket owner has installed an OnSent handler,
+ call it now. */
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ {
+ if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )
+ {
+ pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );
+ }
+ }
+ #endif /* ipconfigUSE_CALLBACKS == 1 */
+ }
+ }
+ }
+
+ /* If this socket has a stream for transmission, add the data to the
+ outgoing segment(s). */
+ if( pxSocket->u.xTCP.txStream != NULL )
+ {
+ prvTCPAddTxData( pxSocket );
+ }
+
+ pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
+
+ if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) )
+ {
+ /* Peer is requesting to stop, see if we're really finished. */
+ xMayClose = pdTRUE;
+
+ /* Checks are only necessary if we haven't sent a FIN yet. */
+ if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
+ {
+ /* xTCPWindowTxDone returns true when all Tx queues are empty. */
+ bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );
+ bTxDone = xTCPWindowTxDone( pxTCPWindow );
+
+ if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )
+ {
+ /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */
+ FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.usRemotePort,
+ bRxComplete, bTxDone ) );
+ xMayClose = pdFALSE;
+ }
+ else
+ {
+ lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber );
+
+ if( lDistance > 1 )
+ {
+ FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n",
+ lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
+ pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );
+
+ xMayClose = pdFALSE;
+ }
+ }
+ }
+
+ if( xTCPWindowLoggingLevel > 0 )
+ {
+ FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n",
+ xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength,
+ pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) );
+ }
+
+ if( xMayClose != pdFALSE )
+ {
+ pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;
+ xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
+ }
+ }
+
+ if( xMayClose == pdFALSE )
+ {
+ pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;
+
+ if( ulReceiveLength != 0u )
+ {
+ xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+ /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */
+ pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+
+ if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
+ {
+ pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;
+ }
+ }
+
+ /* Now get data to be transmitted. */
+ /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP
+ can not send-out both TCP options and also a full packet. Sending
+ options (SACK) is always more urgent than sending data, which can be
+ sent later. */
+ if( uxOptionsLength == 0u )
+ {
+ /* prvTCPPrepareSend might allocate a bigger network buffer, if
+ necessary. */
+ lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
+ if( lSendResult > 0 )
+ {
+ xSendLength = ( BaseType_t ) lSendResult;
+ }
+ }
+ }
+
+ return xSendLength;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Called from prvTCPHandleState(). There is data to be sent. If
+ * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be
+ * checked if it would better be postponed for efficiency.
+ */
+static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,
+ uint32_t ulReceiveLength, BaseType_t xSendLength )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;
+TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
+/* Find out what window size we may advertised. */
+uint32_t ulFrontSpace;
+int32_t lRxSpace;
+#if( ipconfigUSE_TCP_WIN == 1 )
+ #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 )
+ const int32_t lMinLength = 0;
+ #else
+ int32_t lMinLength;
+ #endif
+#endif
+ pxSocket->u.xTCP.ulRxCurWinSize = pxTCPWindow->xSize.ulRxWindowLength -
+ ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber );
+
+ /* Free space in rxStream. */
+ if( pxSocket->u.xTCP.rxStream != NULL )
+ {
+ ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
+ }
+ else
+ {
+ ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;
+ }
+
+ pxSocket->u.xTCP.ulRxCurWinSize = FreeRTOS_min_uint32( ulFrontSpace, pxSocket->u.xTCP.ulRxCurWinSize );
+
+ /* Set the time-out field, so that we'll be called by the IP-task in case no
+ next message will be received. */
+ lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber );
+ #if ipconfigUSE_TCP_WIN == 1
+ {
+
+ #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 )
+ {
+ lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS );
+ }
+ #endif /* ipconfigTCP_ACK_EARLIER_PACKET */
+
+ /* In case we're receiving data continuously, we might postpone sending
+ an ACK to gain performance. */
+ if( ( ulReceiveLength > 0 ) && /* Data was sent to this socket. */
+ ( lRxSpace >= lMinLength ) && /* There is Rx space for more data. */
+ ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) && /* Not in a closure phase. */
+ ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */
+ ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) && /* Connection established. */
+ ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) ) /* There are no other flags than an ACK. */
+ {
+ if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
+ {
+ /* There was still a delayed in queue, delete it. */
+ if( pxSocket->u.xTCP.pxAckMessage != 0 )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
+ }
+
+ pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;
+ }
+ if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) || /* Received a small message. */
+ ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */
+ {
+ pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS );
+ }
+ else
+ {
+ /* Normally a delayed ACK should wait 200 ms for a next incoming
+ packet. Only wait 20 ms here to gain performance. A slow ACK
+ for full-size message. */
+ pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS );
+ }
+
+ if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
+ {
+ FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.usRemotePort,
+ pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
+ pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+ xSendLength,
+ pxSocket->u.xTCP.usTimeout, lRxSpace ) );
+ }
+
+ *ppxNetworkBuffer = NULL;
+ xSendLength = 0;
+ }
+ else if( pxSocket->u.xTCP.pxAckMessage != NULL )
+ {
+ /* As an ACK is not being delayed, remove any earlier delayed ACK
+ message. */
+ if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
+ }
+
+ pxSocket->u.xTCP.pxAckMessage = NULL;
+ }
+ }
+ #else
+ {
+ /* Remove compiler warnings. */
+ ( void ) ulReceiveLength;
+ ( void ) pxTCPHeader;
+ ( void ) lRxSpace;
+ }
+ #endif /* ipconfigUSE_TCP_WIN */
+
+ if( xSendLength != 0 )
+ {
+ if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )
+ {
+ FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.usRemotePort,
+ pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,
+ pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,
+ xSendLength ) );
+ }
+
+ /* Set the parameter 'xReleaseAfterSend' to the value of
+ ipconfigZERO_COPY_TX_DRIVER. */
+ prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* The driver has taken ownership of the Network Buffer. */
+ *ppxNetworkBuffer = NULL;
+ }
+ #endif
+ }
+
+ return xSendLength;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * prvTCPHandleState()
+ * is the most important function of this TCP stack
+ * We've tried to keep it (relatively short) by putting a lot of code in
+ * the static functions above:
+ *
+ * prvCheckRxData()
+ * prvStoreRxData()
+ * prvSetOptions()
+ * prvHandleSynReceived()
+ * prvHandleEstablished()
+ * prvSendData()
+ *
+ * As these functions are declared static, and they're called from one location
+ * only, most compilers will inline them, thus avoiding a call and return.
+ */
+static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
+{
+TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
+TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
+BaseType_t xSendLength = 0;
+uint32_t ulReceiveLength; /* Number of bytes contained in the TCP message. */
+uint8_t *pucRecvData;
+uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);
+
+ /* uxOptionsLength: the size of the options to be sent (always a multiple of
+ 4 bytes)
+ 1. in the SYN phase, we shall communicate the MSS
+ 2. in case of a SACK, Selective ACK, ack a segment which comes in
+ out-of-order. */
+UBaseType_t uxOptionsLength = 0u;
+uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
+TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
+
+ /* First get the length and the position of the received data, if any.
+ pucRecvData will point to the first byte of the TCP payload. */
+ ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );
+
+ if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )
+ {
+ if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )
+ {
+ /* This is most probably a keep-alive message from peer. Setting
+ 'bWinChange' doesn't cause a window-size-change, the flag is used
+ here to force sending an immediate ACK. */
+ pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
+ }
+ }
+
+ /* Keep track of the highest sequence number that might be expected within
+ this connection. */
+ if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )
+ {
+ pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;
+ }
+
+ /* Storing data may result in a fatal error if malloc() fails. */
+ if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )
+ {
+ xSendLength = -1;
+ }
+ else
+ {
+ uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );
+
+ if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )
+ {
+ FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );
+
+ /* In eSYN_RECEIVED a simple ACK is expected, but apparently the
+ 'SYN+ACK' didn't arrive. Step back to the previous state in which
+ a first incoming SYN is handled. The SYN was counted already so
+ decrease it first. */
+ vTCPStateChange( pxSocket, eSYN_FIRST );
+ }
+
+ if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )
+ {
+ /* It's the first time a FIN has been received, remember its
+ sequence number. */
+ pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;
+ pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;
+
+ /* Was peer the first one to send a FIN? */
+ if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
+ {
+ /* If so, don't send the-last-ACK. */
+ pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;
+ }
+ }
+
+ switch (pxSocket->u.xTCP.ucTCPState)
+ {
+ case eCLOSED: /* (server + client) no connection state at all. */
+ /* Nothing to do for a closed socket, except waiting for the
+ owner. */
+ break;
+
+ case eTCP_LISTEN: /* (server) waiting for a connection request from
+ any remote TCP and port. */
+ /* The listen state was handled in xProcessReceivedTCPPacket().
+ Should not come here. */
+ break;
+
+ case eSYN_FIRST: /* (server) Just received a SYN request for a server
+ socket. */
+ {
+ /* A new socket has been created, reply with a SYN+ACK.
+ Acknowledge with seq+1 because the SYN is seen as pseudo data
+ with len = 1. */
+ uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
+ pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;
+
+ xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
+
+ /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and
+ uxOptionsLength is a multiple of 4. The complete expression is:
+ ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
+ pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
+ vTCPStateChange( pxSocket, eSYN_RECEIVED );
+
+ pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
+ pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */
+ }
+ break;
+
+ case eCONNECT_SYN: /* (client) also called SYN_SENT: we've just send a
+ SYN, expect a SYN+ACK and send a ACK now. */
+ /* Fall through */
+ case eSYN_RECEIVED: /* (server) we've had a SYN, replied with SYN+SCK
+ expect a ACK and do nothing. */
+ xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
+ break;
+
+ case eESTABLISHED: /* (server + client) an open connection, data
+ received can be delivered to the user. The normal
+ state for the data transfer phase of the connection
+ The closing states are also handled here with the
+ use of some flags. */
+ xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
+ break;
+
+ case eLAST_ACK: /* (server + client) waiting for an acknowledgement
+ of the connection termination request previously
+ sent to the remote TCP (which includes an
+ acknowledgement of its connection termination
+ request). */
+ /* Fall through */
+ case eFIN_WAIT_1: /* (server + client) waiting for a connection termination request from the remote TCP,
+ * or an acknowledgement of the connection termination request previously sent. */
+ /* Fall through */
+ case eFIN_WAIT_2: /* (server + client) waiting for a connection termination request from the remote TCP. */
+ xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
+ break;
+
+ case eCLOSE_WAIT: /* (server + client) waiting for a connection
+ termination request from the local user. Nothing to
+ do, connection is closed, wait for owner to close
+ this socket. */
+ break;
+
+ case eCLOSING: /* (server + client) waiting for a connection
+ termination request acknowledgement from the remote
+ TCP. */
+ break;
+
+ case eTIME_WAIT: /* (either server or client) waiting for enough time
+ to pass to be sure the remote TCP received the
+ acknowledgement of its connection termination
+ request. [According to RFC 793 a connection can stay
+ in TIME-WAIT for a maximum of four minutes known as
+ a MSL (maximum segment lifetime).] These states are
+ implemented implicitly by settings flags like
+ 'bFinSent', 'bFinRecv', and 'bFinAcked'. */
+ break;
+ default:
+ break;
+ }
+ }
+
+ if( xSendLength > 0 )
+ {
+ xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );
+ }
+
+ return xSendLength;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+ #if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 )
+ {
+ TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+ const BaseType_t xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */
+
+ pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_RST;
+ pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2;
+
+ prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t ) xSendLength, pdFALSE );
+ }
+ #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */
+
+ /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */
+ ( void ) pxNetworkBuffer;
+
+ /* The packet was not consumed. */
+ return pdFAIL;
+}
+/*-----------------------------------------------------------*/
+
+static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket )
+{
+uint32_t ulMSS = ipconfigTCP_MSS;
+
+ if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul )
+ {
+ /* Data for this peer will pass through a router, and maybe through
+ the internet. Limit the MSS to 1400 bytes or less. */
+ ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS );
+ }
+
+ FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );
+
+ pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * FreeRTOS_TCP_IP has only 2 public functions, this is the second one:
+ * xProcessReceivedTCPPacket()
+ * prvTCPHandleState()
+ * prvTCPPrepareSend()
+ * prvTCPReturnPacket()
+ * xNetworkInterfaceOutput() // Sends data to the NIC
+ * prvTCPSendRepeated()
+ * prvTCPReturnPacket() // Prepare for returning
+ * xNetworkInterfaceOutput() // Sends data to the NIC
+*/
+BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+FreeRTOS_Socket_t *pxSocket;
+TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+uint16_t ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags;
+uint32_t ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress );
+uint16_t xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort );
+uint32_t ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
+uint16_t xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
+BaseType_t xResult = pdPASS;
+
+ /* Find the destination socket, and if not found: return a socket listing to
+ the destination PORT. */
+ pxSocket = ( FreeRTOS_Socket_t * ) pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort );
+
+ if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) )
+ {
+ /* A TCP messages is received but either there is no socket with the
+ given port number or the there is a socket, but it is in one of these
+ non-active states: eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or
+ eTIME_WAIT. */
+
+ FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) );
+
+ /* Send a RST to all packets that can not be handled. As a result
+ the other party will get a ECONN error. There are two exceptions:
+ 1) A packet that already has the RST flag set.
+ 2) A packet that only has the ACK flag set.
+ A packet with only the ACK flag set might be the last ACK in
+ a three-way hand-shake that closes a connection. */
+ if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) &&
+ ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) )
+ {
+ prvTCPSendReset( pxNetworkBuffer );
+ }
+
+ /* The packet can't be handled. */
+ xResult = pdFAIL;
+ }
+ else
+ {
+ pxSocket->u.xTCP.ucRepCount = 0u;
+
+ if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
+ {
+ /* The matching socket is in a listening state. Test if the peer
+ has set the SYN flag. */
+ if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN )
+ {
+ /* What happens: maybe after a reboot, a client doesn't know the
+ connection had gone. Send a RST in order to get a new connect
+ request. */
+ #if( ipconfigHAS_DEBUG_PRINTF == 1 )
+ {
+ FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n",
+ prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) );
+ }
+ #endif /* ipconfigHAS_DEBUG_PRINTF */
+
+ if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u )
+ {
+ prvTCPSendReset( pxNetworkBuffer );
+ }
+ xResult = pdFAIL;
+ }
+ else
+ {
+ /* prvHandleListen() will either return a newly created socket
+ (if bReuseSocket is false), otherwise it returns the current
+ socket which will later get connected. */
+ pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );
+
+ if( pxSocket == NULL )
+ {
+ xResult = pdFAIL;
+ }
+ }
+ } /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */
+ else
+ {
+ /* This is not a socket in listening mode. Check for the RST
+ flag. */
+ if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u )
+ {
+ /* The target socket is not in a listening state, any RST packet
+ will cause the socket to be closed. */
+ FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) );
+ /* _HT_: should indicate that 'ECONNRESET' must be returned to the used during next API. */
+ vTCPStateChange( pxSocket, eCLOSED );
+
+ /* The packet cannot be handled. */
+ xResult = pdFAIL;
+ }
+ else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) )
+ {
+ /* SYN flag while this socket is already connected. */
+ FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) );
+
+ /* The packet cannot be handled. */
+ xResult = pdFAIL;
+ }
+ else
+ {
+ /* Update the copy of the TCP header only (skipping eth and IP
+ headers). It might be used later on, whenever data must be sent
+ to the peer. */
+ const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER );
+ memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER );
+ }
+ }
+ }
+
+ if( xResult != pdFAIL )
+ {
+ /* Touch the alive timers because we received a message for this
+ socket. */
+ prvTCPTouchSocket( pxSocket );
+
+ /* Parse the TCP option(s), if present. */
+ /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,
+ then we MUST assume an MSS size of 536 bytes for backward compatibility. */
+
+ /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as
+ the number 5 (words) in the higher niblle of the TCP-offset byte. */
+ if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH )
+ {
+ prvCheckOptions( pxSocket, pxNetworkBuffer );
+ }
+
+
+ #if( ipconfigUSE_TCP_WIN == 1 )
+ {
+ pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow );
+ pxSocket->u.xTCP.ulWindowSize =
+ ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );
+ }
+ #endif
+
+ /* In prvTCPHandleState() the incoming messages will be handled
+ depending on the current state of the connection. */
+ if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )
+ {
+ /* prvTCPHandleState() has sent a message, see if there are more to
+ be transmitted. */
+ #if( ipconfigUSE_TCP_WIN == 1 )
+ {
+ prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );
+ }
+ #endif /* ipconfigUSE_TCP_WIN */
+ }
+
+ if( pxNetworkBuffer != NULL )
+ {
+ /* We must check if the buffer is unequal to NULL, because the
+ socket might keep a reference to it in case a delayed ACK must be
+ sent. */
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ pxNetworkBuffer = NULL;
+ }
+
+ /* And finally, calculate when this socket wants to be woken up. */
+ prvTCPNextTimeout ( pxSocket );
+ /* Return pdPASS to tell that the network buffer is 'consumed'. */
+ xResult = pdPASS;
+ }
+
+ /* pdPASS being returned means the buffer has been consumed. */
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )
+{
+TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+FreeRTOS_Socket_t *pxReturn;
+
+ /* A pure SYN (without ACK) has come in, create a new socket to answer
+ it. */
+ if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
+ {
+ /* The flag bReuseSocket indicates that the same instance of the
+ listening socket should be used for the connection. */
+ pxReturn = pxSocket;
+ pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
+ pxSocket->u.xTCP.pxPeerSocket = pxSocket;
+ }
+ else
+ {
+ /* The socket does not have the bReuseSocket flag set meaning create a
+ new socket when a connection comes in. */
+ pxReturn = NULL;
+
+ if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )
+ {
+ FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.usChildCount,
+ pxSocket->u.xTCP.usBacklog,
+ pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) );
+ prvTCPSendReset( pxNetworkBuffer );
+ }
+ else
+ {
+ FreeRTOS_Socket_t *pxNewSocket = (FreeRTOS_Socket_t *)
+ FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
+
+ if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) )
+ {
+ FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) );
+ prvTCPSendReset( pxNetworkBuffer );
+ }
+ else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE )
+ {
+ /* The socket will be connected immediately, no time for the
+ owner to setsockopt's, therefore copy properties of the server
+ socket to the new socket. Only the binding might fail (due to
+ lack of resources). */
+ pxReturn = pxNewSocket;
+ }
+ }
+ }
+
+ if( pxReturn != NULL )
+ {
+ pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );
+ pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );
+ pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber;
+
+ /* Here is the SYN action. */
+ pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );
+ prvSocketSetMSS( pxReturn );
+
+ prvTCPCreateWindow( pxReturn );
+
+ /* It is recommended to increase the ISS for each new connection with a value of 0x102. */
+ ulNextInitialSequenceNumber += INITIAL_SEQUENCE_NUMBER_INCREMENT;
+
+ vTCPStateChange( pxReturn, eSYN_FIRST );
+
+ /* Make a copy of the header up to the TCP header. It is needed later
+ on, whenever data must be sent to the peer. */
+ memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) );
+ }
+ return pxReturn;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Duplicates a socket after a listening socket receives a connection.
+ */
+static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket )
+{
+struct freertos_sockaddr xAddress;
+
+ pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;
+ pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;
+ pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;
+ pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;
+ pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;
+ pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;
+ pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;
+ pxNewSocket->u.xTCP.uxRxWinSize = pxSocket->u.xTCP.uxRxWinSize;
+ pxNewSocket->u.xTCP.uxTxWinSize = pxSocket->u.xTCP.uxTxWinSize;
+
+ #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
+ {
+ pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;
+ }
+ #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
+
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ {
+ /* In case call-backs are used, copy them from parent to child. */
+ pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;
+ pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;
+ pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;
+ }
+ #endif /* ipconfigUSE_CALLBACKS */
+
+ #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+ {
+ /* Child socket of listening sockets will inherit the Socket Set
+ Otherwise the owner has no chance of including it into the set. */
+ if( pxSocket->pxSocketSet )
+ {
+ pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;
+ pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT;
+ }
+ }
+ #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
+
+ /* And bind it to the same local port as its parent. */
+ xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
+ xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
+
+ #if( ipconfigTCP_HANG_PROTECTION == 1 )
+ {
+ /* Only when there is anti-hanging protection, a socket may become an
+ orphan temporarily. Once this socket is really connected, the owner of
+ the server socket will be notified. */
+
+ /* When bPassQueued is true, the socket is an orphan until it gets
+ connected. */
+ pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;
+ pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;
+ }
+ #else
+ {
+ /* A reference to the new socket may be stored and the socket is marked
+ as 'passable'. */
+
+ /* When bPassAccept is true, this socket may be returned in a call to
+ accept(). */
+ pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;
+ if(pxSocket->u.xTCP.pxPeerSocket == NULL )
+ {
+ pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;
+ }
+ }
+ #endif
+
+ pxSocket->u.xTCP.usChildCount++;
+
+ FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",
+ pxSocket->usLocalPort,
+ pxSocket->u.xTCP.usChildCount,
+ pxSocket->u.xTCP.usBacklog,
+ pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );
+
+ /* Now bind the child socket to the same port as the listening socket. */
+ if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )
+ {
+ FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );
+ vSocketClose( pxNewSocket );
+ return pdFALSE;
+ }
+
+ return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )
+
+ const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )
+ {
+ if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) )
+ {
+ ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u;
+ }
+ return pcStateNames[ ulState ];
+ }
+
+#endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */
+/*-----------------------------------------------------------*/
+
+/*
+ * In the API accept(), the user asks is there is a new client? As API's can
+ * not walk through the xBoundTCPSocketsList the IP-task will do this.
+ */
+BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket )
+{
+TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort );
+ListItem_t *pxIterator;
+FreeRTOS_Socket_t *pxFound;
+BaseType_t xResult = pdFALSE;
+
+ /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one
+ who has access. */
+ for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
+ pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
+ pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
+ {
+ if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort )
+ {
+ pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+ if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
+ {
+ pxSocket->u.xTCP.pxPeerSocket = pxFound;
+ FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );
+ xResult = pdTRUE;
+ break;
+ }
+ }
+ }
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+#endif /* ipconfigUSE_TCP == 1 */
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c
new file mode 100644
index 000000000..85e948039
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c
@@ -0,0 +1,2009 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*
+ * FreeRTOS_TCP_WIN.c
+ * Module which handles the TCP windowing schemes for FreeRTOS+TCP. Many
+ * functions have two versions - one for FreeRTOS+TCP (full) and one for
+ * FreeRTOS+TCP (lite).
+ *
+ * In this module all ports and IP addresses and sequence numbers are
+ * being stored in host byte-order.
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "NetworkBufferManagement.h"
+#include "FreeRTOS_TCP_WIN.h"
+
+/* Constants used for Smoothed Round Trip Time (SRTT). */
+#define winSRTT_INCREMENT_NEW 2
+#define winSRTT_INCREMENT_CURRENT 6
+#define winSRTT_DECREMENT_NEW 1
+#define winSRTT_DECREMENT_CURRENT 7
+#define winSRTT_CAP_mS 50
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE )
+
+ #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE )
+
+ /* The code to send a single Selective ACK (SACK):
+ * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a),
+ * followed by a lower and a higher sequence number,
+ * where LEN is 2 + 2*4 = 10 bytes. */
+ #if( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
+ #define OPTION_CODE_SINGLE_SACK ( 0x0101050aUL )
+ #else
+ #define OPTION_CODE_SINGLE_SACK ( 0x0a050101UL )
+ #endif
+
+ /* Normal retransmission:
+ * A packet will be retransmitted after a Retransmit Time-Out (RTO).
+ * Fast retransmission:
+ * When 3 packets with a higher sequence number have been acknowledged
+ * by the peer, it is very unlikely a current packet will ever arrive.
+ * It will be retransmitted far before the RTO.
+ */
+ #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ( 3u )
+
+ /* If there have been several retransmissions (4), decrease the
+ * size of the transmission window to at most 2 times MSS.
+ */
+ #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ( 4u )
+
+#endif /* configUSE_TCP_WIN */
+/*-----------------------------------------------------------*/
+
+extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
+
+/*
+ * All TCP sockets share a pool of segment descriptors (TCPSegment_t)
+ * Available descriptors are stored in the 'xSegmentList'
+ * When a socket owns a descriptor, it will either be stored in
+ * 'xTxSegments' or 'xRxSegments'
+ * As soon as a package has been confirmed, the descriptor will be returned
+ * to the segment pool
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static BaseType_t prvCreateSectors( void );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * Find a segment with a given sequence number in the list of received
+ * segments: 'pxWindow->xRxSegments'.
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * Allocate a new segment
+ * The socket will borrow all segments from a common pool: 'xSegmentList',
+ * which is a list of 'TCPSegment_t'
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/* When the peer has a close request (FIN flag), the driver will check if
+ * there are missing packets in the Rx-queue
+ * It will accept the closure of the connection if both conditions are true:
+ * - the Rx-queue is empty
+ * - we've ACK'd the highest Rx sequence number seen
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * Detaches and returns the head of a queue
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static TCPSegment_t *xTCPWindowGetHead( List_t *pxList );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * Returns the head of a queue but it won't be detached
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * Free entry pxSegment because it's not used anymore
+ * The ownership will be passed back to the segment pool
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static void vTCPWindowFree( TCPSegment_t *pxSegment );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * A segment has been received with sequence number 'ulSequenceNumber', where
+ * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this
+ * segment was expected. xTCPWindowRxConfirm() will check if there is already
+ * another segment with a sequence number between (ulSequenceNumber) and
+ * (ulSequenceNumber+xLength). Normally none will be found, because the next Rx
+ * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'.
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * FreeRTOS+TCP stores data in circular buffers. Calculate the next position to
+ * store.
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * This function will look if there is new transmission data. It will return
+ * true if there is data to be sent.
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * An acknowledge was received. See if some outstanding data may be removed
+ * from the transmission queue(s).
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*
+ * A higher Tx block has been acknowledged. Now iterate through the xWaitQueue
+ * to find a possible condition for a FAST retransmission.
+ */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst );
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/*-----------------------------------------------------------*/
+
+/* TCP segement pool. */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static TCPSegment_t *xTCPSegments = NULL;
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+
+/* List of free TCP segments. */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static List_t xSegmentList;
+#endif
+
+/* Logging verbosity level. */
+BaseType_t xTCPWindowLoggingLevel = 0;
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+ /* Some 32-bit arithmetic: comparing sequence numbers */
+ static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b );
+ static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b )
+ {
+ /* Test if a <= b
+ Return true if the unsigned subtraction of (b-a) doesn't generate an
+ arithmetic overflow. */
+ return ( ( b - a ) & 0x80000000UL ) == 0UL;
+ }
+#endif /* ipconfigUSE_TCP_WIN */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b );
+ static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b )
+ {
+ /* Test if a < b */
+ return ( ( b - a - 1UL ) & 0x80000000UL ) == 0UL;
+ }
+#endif /* ipconfigUSE_TCP_WIN */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b );
+ static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b )
+ {
+ /* Test if a > b */
+ return ( ( a - b - 1UL ) & 0x80000000UL ) == 0UL;
+ }
+#endif /* ipconfigUSE_TCP_WIN */
+
+/*-----------------------------------------------------------*/
+static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b );
+static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b )
+{
+ /* Test if a >= b */
+ return ( ( a - b ) & 0x80000000UL ) == 0UL;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+ static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem );
+ static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem )
+ {
+ vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd );
+ }
+#endif
+/*-----------------------------------------------------------*/
+
+static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer );
+static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer )
+{
+ pxTimer->ulBorn = xTaskGetTickCount ( );
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer );
+static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer )
+{
+ return ( ( xTaskGetTickCount() - pxTimer->ulBorn ) * portTICK_PERIOD_MS );
+}
+/*-----------------------------------------------------------*/
+
+/* _HT_ GCC (using the settings that I'm using) checks for every public function if it is
+preceded by a prototype. Later this prototype will be located in list.h? */
+
+extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere );
+
+void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere )
+{
+ /* Insert a new list item into pxList, it does not sort the list,
+ but it puts the item just before xListEnd, so it will be the last item
+ returned by listGET_HEAD_ENTRY() */
+ pxNewListItem->pxNext = (struct xLIST_ITEM * configLIST_VOLATILE)pxWhere;
+ pxNewListItem->pxPrevious = pxWhere->pxPrevious;
+ pxWhere->pxPrevious->pxNext = pxNewListItem;
+ pxWhere->pxPrevious = pxNewListItem;
+
+ /* Remember which list the item is in. */
+ pxNewListItem->pvContainer = ( void * ) pxList;
+
+ ( pxList->uxNumberOfItems )++;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ static BaseType_t prvCreateSectors( void )
+ {
+ BaseType_t xIndex, xReturn;
+
+ /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */
+
+ vListInitialise( &xSegmentList );
+ xTCPSegments = ( TCPSegment_t * ) pvPortMallocLarge( ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
+
+ if( xTCPSegments == NULL )
+ {
+ FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %lu failed\n",
+ ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) );
+
+ xReturn = pdFAIL;
+ }
+ else
+ {
+ /* Clear the allocated space. */
+ memset( xTCPSegments, '\0', ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) );
+
+ for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ )
+ {
+ /* Could call vListInitialiseItem here but all data has been
+ nulled already. Set the owner to a segment descriptor. */
+ listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xListItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
+ listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void* ) &( xTCPSegments[ xIndex ] ) );
+
+ /* And add it to the pool of available segments */
+ vListInsertFifo( &xSegmentList, &( xTCPSegments[xIndex].xListItem ) );
+ }
+
+ xReturn = pdPASS;
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
+ {
+ const ListItem_t *pxIterator;
+ const MiniListItem_t* pxEnd;
+ TCPSegment_t *pxSegment, *pxReturn = NULL;
+
+ /* Find a segment with a given sequence number in the list of received
+ segments. */
+
+ pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xRxSegments );
+
+ for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
+ pxIterator != ( const ListItem_t * ) pxEnd;
+ pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
+ {
+ pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+
+ if( pxSegment->ulSequenceNumber == ulSequenceNumber )
+ {
+ pxReturn = pxSegment;
+ break;
+ }
+ }
+
+ return pxReturn;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx )
+ {
+ TCPSegment_t *pxSegment;
+ ListItem_t * pxItem;
+
+ /* Allocate a new segment. The socket will borrow all segments from a
+ common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */
+ if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE )
+ {
+ /* If the TCP-stack runs out of segments, you might consider
+ increasing 'ipconfigTCP_WIN_SEG_COUNT'. */
+ FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", xIsForRx ? 'R' : 'T' ) );
+ pxSegment = NULL;
+ }
+ else
+ {
+ /* Pop the item at the head of the list. Semaphore protection is
+ not required as only the IP task will call these functions. */
+ pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList );
+ pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
+
+ configASSERT( pxItem != NULL );
+ configASSERT( pxSegment != NULL );
+
+ /* Remove the item from xSegmentList. */
+ uxListRemove( pxItem );
+
+ /* Add it to either the connections' Rx or Tx queue. */
+ vListInsertFifo( xIsForRx ? &pxWindow->xRxSegments : &pxWindow->xTxSegments, pxItem );
+
+ /* And set the segment's timer to zero */
+ vTCPTimerSet( &pxSegment->xTransmitTimer );
+
+ pxSegment->u.ulFlags = 0;
+ pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 );
+ pxSegment->lMaxLength = lCount;
+ pxSegment->lDataLength = lCount;
+ pxSegment->ulSequenceNumber = ulSequenceNumber;
+ #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+ {
+ static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT;
+ UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList );
+
+ if( xLowestLength > xLength )
+ {
+ xLowestLength = xLength;
+ }
+ }
+ #endif /* ipconfigHAS_DEBUG_PRINTF */
+ }
+
+ return pxSegment;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
+ {
+ BaseType_t xReturn;
+
+ /* When the peer has a close request (FIN flag), the driver will check
+ if there are missing packets in the Rx-queue. It will accept the
+ closure of the connection if both conditions are true:
+ - the Rx-queue is empty
+ - the highest Rx sequence number has been ACK'ed */
+ if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE )
+ {
+ /* Rx data has been stored while earlier packets were missing. */
+ xReturn = pdFALSE;
+ }
+ else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE )
+ {
+ /* No Rx packets are being stored and the highest sequence number
+ that has been received has been ACKed. */
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %lu highest %lu (empty)\n",
+ ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ),
+ ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) );
+ xReturn = pdFALSE;
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ static TCPSegment_t *xTCPWindowGetHead( List_t *pxList )
+ {
+ TCPSegment_t *pxSegment;
+ ListItem_t * pxItem;
+
+ /* Detaches and returns the head of a queue. */
+ if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
+ {
+ pxSegment = NULL;
+ }
+ else
+ {
+ pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
+ pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
+
+ uxListRemove( pxItem );
+ }
+
+ return pxSegment;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList )
+ {
+ ListItem_t *pxItem;
+ TCPSegment_t *pxReturn;
+
+ /* Returns the head of a queue but it won't be detached. */
+ if( listLIST_IS_EMPTY( pxList ) != pdFALSE )
+ {
+ pxReturn = NULL;
+ }
+ else
+ {
+ pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList );
+ pxReturn = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem );
+ }
+
+ return pxReturn;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ static void vTCPWindowFree( TCPSegment_t *pxSegment )
+ {
+ /* Free entry pxSegment because it's not used any more. The ownership
+ will be passed back to the segment pool.
+
+ Unlink it from one of the queues, if any. */
+ if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL )
+ {
+ uxListRemove( &( pxSegment->xQueueItem ) );
+ }
+
+ pxSegment->ulSequenceNumber = 0u;
+ pxSegment->lDataLength = 0l;
+ pxSegment->u.ulFlags = 0u;
+
+ /* Take it out of xRxSegments/xTxSegments */
+ if( listLIST_ITEM_CONTAINER( &( pxSegment->xListItem ) ) != NULL )
+ {
+ uxListRemove( &( pxSegment->xListItem ) );
+ }
+
+ /* Return it to xSegmentList */
+ vListInsertFifo( &xSegmentList, &( pxSegment->xListItem ) );
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ void vTCPWindowDestroy( TCPWindow_t *pxWindow )
+ {
+ List_t * pxSegments;
+ BaseType_t xRound;
+ TCPSegment_t *pxSegment;
+
+ /* Destroy a window. A TCP window doesn't serve any more. Return all
+ owned segments to the pool. In order to save code, it will make 2 rounds,
+ one to remove the segments from xRxSegments, and a second round to clear
+ xTxSegments*/
+ for( xRound = 0; xRound < 2; xRound++ )
+ {
+ if( xRound != 0 )
+ {
+ pxSegments = &( pxWindow->xRxSegments );
+ }
+ else
+ {
+ pxSegments = &( pxWindow->xTxSegments );
+ }
+
+ if( listLIST_IS_INITIALISED( pxSegments ) != pdFALSE )
+ {
+ while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U )
+ {
+ pxSegment = ( TCPSegment_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxSegments );
+ vTCPWindowFree( pxSegment );
+ }
+ }
+ }
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength,
+ uint32_t ulTxWindowLength, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
+{
+ /* Create and initialize a window. */
+
+ #if( ipconfigUSE_TCP_WIN == 1 )
+ {
+ if( xTCPSegments == NULL )
+ {
+ prvCreateSectors();
+ }
+
+ vListInitialise( &( pxWindow->xTxSegments ) );
+ vListInitialise( &( pxWindow->xRxSegments ) );
+
+ vListInitialise( &( pxWindow->xPriorityQueue ) ); /* Priority queue: segments which must be sent immediately */
+ vListInitialise( &( pxWindow->xTxQueue ) ); /* Transmit queue: segments queued for transmission */
+ vListInitialise( &( pxWindow->xWaitQueue ) ); /* Waiting queue: outstanding segments */
+ }
+ #endif /* ipconfigUSE_TCP_WIN == 1 */
+
+ if( xTCPWindowLoggingLevel != 0 )
+ {
+ FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %lu/%lu\n",
+ ulRxWindowLength, ulTxWindowLength ) );
+ }
+
+ pxWindow->xSize.ulRxWindowLength = ulRxWindowLength;
+ pxWindow->xSize.ulTxWindowLength = ulTxWindowLength;
+
+ vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS );
+}
+/*-----------------------------------------------------------*/
+
+void vTCPWindowInit( TCPWindow_t *pxWindow, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS )
+{
+const int32_t l500ms = 500;
+
+ pxWindow->u.ulFlags = 0ul;
+ pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED;
+
+ if( ulMSS != 0ul )
+ {
+ if( pxWindow->usMSSInit != 0u )
+ {
+ pxWindow->usMSSInit = ( uint16_t ) ulMSS;
+ }
+
+ if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0u ) )
+ {
+ pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS;
+ pxWindow->usMSS = ( uint16_t ) ulMSS;
+ }
+ }
+
+ #if( ipconfigUSE_TCP_WIN == 0 )
+ {
+ pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS;
+ }
+ #endif /* ipconfigUSE_TCP_WIN == 1 */
+
+ /*Start with a timeout of 2 * 500 ms (1 sec). */
+ pxWindow->lSRTT = l500ms;
+
+ /* Just for logging, to print relative sequence numbers. */
+ pxWindow->rx.ulFirstSequenceNumber = ulAckNumber;
+
+ /* The segment asked for in the next transmission. */
+ pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber;
+
+ /* The right-hand side of the receive window. */
+ pxWindow->rx.ulHighestSequenceNumber = ulAckNumber;
+
+ pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber;
+
+ /* The segment asked for in next transmission. */
+ pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber;
+
+ /* The sequence number given to the next outgoing byte to be added is
+ maintained by lTCPWindowTxAdd(). */
+ pxWindow->ulNextTxSequenceNumber = ulSequenceNumber;
+
+ /* The right-hand side of the transmit window. */
+ pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber;
+ pxWindow->ulOurSequenceNumber = ulSequenceNumber;
+}
+/*-----------------------------------------------------------*/
+
+/*=============================================================================
+ *
+ * ###### # #
+ * # # # #
+ * # # # #
+ * # # ####
+ * ###### ##
+ * # ## ####
+ * # # # #
+ * # # # #
+ * ### ## # #
+ * Rx functions
+ *
+ *=============================================================================*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength )
+ {
+ TCPSegment_t *pxBest = NULL;
+ const ListItem_t *pxIterator;
+ uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength;
+ const MiniListItem_t* pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &pxWindow->xRxSegments );
+ TCPSegment_t *pxSegment;
+
+ /* A segment has been received with sequence number 'ulSequenceNumber',
+ where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that
+ exactly this segment was expected. xTCPWindowRxConfirm() will check if
+ there is already another segment with a sequence number between (ulSequenceNumber)
+ and (ulSequenceNumber+ulLength). Normally none will be found, because
+ the next RX segment should have a sequence number equal to
+ '(ulSequenceNumber+ulLength)'. */
+
+ /* Iterate through all RX segments that are stored: */
+ for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
+ pxIterator != ( const ListItem_t * ) pxEnd;
+ pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
+ {
+ pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+ /* And see if there is a segment for which:
+ 'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber'
+ If there are more matching segments, the one with the lowest sequence number
+ shall be taken */
+ if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) &&
+ ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) )
+ {
+ if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) )
+ {
+ pxBest = pxSegment;
+ }
+ }
+ }
+
+ if( ( pxBest != NULL ) &&
+ ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) )
+ {
+ FreeRTOS_flush_logging();
+ FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %lu (+%ld=%lu) found %lu (+%ld=%lu)\n",
+ pxWindow->usPeerPortNumber,
+ ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+ ulLength,
+ ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber,
+ pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+ pxBest->lDataLength,
+ pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) );
+ }
+
+ return pxBest;
+ }
+
+#endif /* ipconfgiUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
+ {
+ uint32_t ulCurrentSequenceNumber, ulLast, ulSavedSequenceNumber;
+ int32_t lReturn, lDistance;
+ TCPSegment_t *pxFound;
+
+ /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed
+ directly to user (segment is expected). If it returns a positive
+ number, an earlier packet is missing, but this packet may be stored.
+ If negative, the packet has already been stored, or it is out-of-order,
+ or there is not enough space.
+
+ As a side-effect, pxWindow->ulUserDataLength will get set to non-zero,
+ if more Rx data may be passed to the user after this packet. */
+
+ ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber;
+
+ /* For Selective Ack (SACK), used when out-of-sequence data come in. */
+ pxWindow->ucOptionLength = 0u;
+
+ /* Non-zero if TCP-windows contains data which must be popped. */
+ pxWindow->ulUserDataLength = 0ul;
+
+ if( ulCurrentSequenceNumber == ulSequenceNumber )
+ {
+ /* This is the packet with the lowest sequence number we're waiting
+ for. It can be passed directly to the rx stream. */
+ if( ulLength > ulSpace )
+ {
+ FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu bytes, due to lack of space (%lu)\n", ulLength, ulSpace ) );
+ lReturn = -1;
+ }
+ else
+ {
+ ulCurrentSequenceNumber += ulLength;
+
+ if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0 )
+ {
+ ulSavedSequenceNumber = ulCurrentSequenceNumber;
+
+ /* See if (part of) this segment has been stored already,
+ but this rarely happens. */
+ pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength );
+ if( pxFound != NULL )
+ {
+ ulCurrentSequenceNumber = pxFound->ulSequenceNumber + ( ( uint32_t ) pxFound->lDataLength );
+
+ /* Remove it because it will be passed to user directly. */
+ vTCPWindowFree( pxFound );
+ }
+
+ /* Check for following segments that are already in the
+ queue and increment ulCurrentSequenceNumber. */
+ while( ( pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber ) ) != NULL )
+ {
+ ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength;
+
+ /* As all packet below this one have been passed to the
+ user it can be discarded. */
+ vTCPWindowFree( pxFound );
+ }
+
+ if( ulSavedSequenceNumber != ulCurrentSequenceNumber )
+ {
+ /* After the current data-package, there is more data
+ to be popped. */
+ pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber;
+
+ if( xTCPWindowLoggingLevel >= 1 )
+ {
+ FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: retran %lu (Found %lu bytes at %lu cnt %ld)\n",
+ pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
+ ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+ pxWindow->ulUserDataLength,
+ ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+ listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
+ }
+ }
+ }
+
+ pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber;
+
+ /* Packet was expected, may be passed directly to the socket
+ buffer or application. Store the packet at offset 0. */
+ lReturn = 0;
+ }
+ }
+ else if( ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) )
+ {
+ /* Looks like a TCP keep-alive message. Do not accept/store Rx data
+ ulUserDataLength = 0. Not packet out-of-sync. Just reply to it. */
+ lReturn = -1;
+ }
+ else
+ {
+ /* The packet is not the one expected. See if it falls within the Rx
+ window so it can be stored. */
+
+ /* An "out-of-sequence" segment was received, must have missed one.
+ Prepare a SACK (Selective ACK). */
+ ulLast = ulSequenceNumber + ulLength;
+ lDistance = ( int32_t ) ( ulLast - ulCurrentSequenceNumber );
+
+ if( lDistance <= 0 )
+ {
+ /* An earlier has been received, must be a retransmission of a
+ packet that has been accepted already. No need to send out a
+ Selective ACK (SACK). */
+ lReturn = -1;
+ }
+ else if( lDistance > ( int32_t ) ulSpace )
+ {
+ /* The new segment is ahead of rx.ulCurrentSequenceNumber. The
+ sequence number of this packet is too far ahead, ignore it. */
+ FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu+%lu bytes, due to lack of space (%lu)\n", lDistance, ulLength, ulSpace ) );
+ lReturn = -1;
+ }
+ else
+ {
+ /* See if there is more data in a contiguous block to make the
+ SACK describe a longer range of data. */
+
+ /* TODO: SACK's may also be delayed for a short period
+ * This is useful because subsequent packets will be SACK'd with
+ * single one message
+ */
+ while( ( pxFound = xTCPWindowRxFind( pxWindow, ulLast ) ) != NULL )
+ {
+ ulLast += ( uint32_t ) pxFound->lDataLength;
+ }
+
+ if( xTCPWindowLoggingLevel >= 1 )
+ {
+ FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %lu exp %lu (dist %ld) SACK to %lu\n",
+ pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
+ ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+ ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+ ( BaseType_t ) ( ulSequenceNumber - ulCurrentSequenceNumber ), /* want this signed */
+ ulLast - pxWindow->rx.ulFirstSequenceNumber ) );
+ }
+
+ /* Now prepare the SACK message.
+ Code OPTION_CODE_SINGLE_SACK already in network byte order. */
+ pxWindow->ulOptionsData[0] = OPTION_CODE_SINGLE_SACK;
+
+ /* First sequence number that we received. */
+ pxWindow->ulOptionsData[1] = FreeRTOS_htonl( ulSequenceNumber );
+
+ /* Last + 1 */
+ pxWindow->ulOptionsData[2] = FreeRTOS_htonl( ulLast );
+
+ /* Which make 12 (3*4) option bytes. */
+ pxWindow->ucOptionLength = 3 * sizeof( pxWindow->ulOptionsData[ 0 ] );
+
+ pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber );
+
+ if( pxFound != NULL )
+ {
+ /* This out-of-sequence packet has been received for a
+ second time. It is already stored but do send a SACK
+ again. */
+ lReturn = -1;
+ }
+ else
+ {
+ pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength );
+
+ if( pxFound == NULL )
+ {
+ /* Can not send a SACK, because the segment cannot be
+ stored. */
+ pxWindow->ucOptionLength = 0u;
+
+ /* Needs to be stored but there is no segment
+ available. */
+ lReturn = -1;
+ }
+ else
+ {
+ if( xTCPWindowLoggingLevel != 0 )
+ {
+ FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %lu (cnt %lu)\n",
+ pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber,
+ listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) );
+ FreeRTOS_flush_logging( );
+ }
+
+ /* Return a positive value. The packet may be accepted
+ and stored but an earlier packet is still missing. */
+ lReturn = ( int32_t ) ( ulSequenceNumber - ulCurrentSequenceNumber );
+ }
+ }
+ }
+ }
+
+ return lReturn;
+ }
+
+#endif /* ipconfgiUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+/*=============================================================================
+ *
+ * ######### # #
+ * # # # # #
+ * # # #
+ * # ####
+ * # ##
+ * # ####
+ * # # #
+ * # # #
+ * ##### # #
+ *
+ * Tx functions
+ *
+ *=============================================================================*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount )
+ {
+ /* +TCP stores data in circular buffers. Calculate the next position to
+ store. */
+ lPosition += lCount;
+ if( lPosition >= lMax )
+ {
+ lPosition -= lMax;
+ }
+
+ return lPosition;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
+ {
+ int32_t lBytesLeft = ( int32_t ) ulLength, lToWrite;
+ int32_t lDone = 0;
+ TCPSegment_t *pxSegment = pxWindow->pxHeadSegment;
+
+ /* Puts a message in the Tx-window (after buffer size has been
+ verified). */
+ if( pxSegment != NULL )
+ {
+ if( pxSegment->lDataLength < pxSegment->lMaxLength )
+ {
+ if( ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength != 0 ) )
+ {
+ /* Adding data to a segment that was already in the TX queue. It
+ will be filled-up to a maximum of MSS (maximum segment size). */
+ lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength );
+
+ pxSegment->lDataLength += lToWrite;
+
+ if( pxSegment->lDataLength >= pxSegment->lMaxLength )
+ {
+ /* This segment is full, don't add more bytes. */
+ pxWindow->pxHeadSegment = NULL;
+ }
+
+ lBytesLeft -= lToWrite;
+
+ /* ulNextTxSequenceNumber is the sequence number of the next byte to
+ be stored for transmission. */
+ pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
+
+ /* Increased the return value. */
+ lDone += lToWrite;
+
+ /* Some detailed logging, for those who're interested. */
+ if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
+ {
+ FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4lu bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
+ ulLength,
+ pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ pxSegment->lDataLength,
+ pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ pxSegment->lStreamPos ) );
+ FreeRTOS_flush_logging( );
+ }
+
+ /* Calculate the next position in the circular data buffer, knowing
+ its maximum length 'lMax'. */
+ lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
+ }
+ }
+ }
+
+ while( lBytesLeft > 0 )
+ {
+ /* The current transmission segment is full, create new segments as
+ needed. */
+ pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, pxWindow->usMSS );
+
+ if( pxSegment != NULL )
+ {
+ /* Store as many as needed, but no more than the maximum
+ (MSS). */
+ lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength );
+
+ pxSegment->lDataLength = lToWrite;
+ pxSegment->lStreamPos = lPosition;
+ lBytesLeft -= lToWrite;
+ lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite );
+ pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite;
+ lDone += lToWrite;
+
+ /* Link this segment in the Tx-Queue. */
+ vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) );
+
+ /* Let 'pxHeadSegment' point to this segment if there is still
+ space. */
+ if( pxSegment->lDataLength < pxSegment->lMaxLength )
+ {
+ pxWindow->pxHeadSegment = pxSegment;
+ }
+ else
+ {
+ pxWindow->pxHeadSegment = NULL;
+ }
+
+ if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 )
+ {
+ if( ( xTCPWindowLoggingLevel >= 3 ) ||
+ ( ( xTCPWindowLoggingLevel >= 2 ) && ( pxWindow->pxHeadSegment != NULL ) ) )
+ {
+ FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: New %4ld bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n",
+ ulLength,
+ pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ pxSegment->lDataLength,
+ pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ pxSegment->lStreamPos ) );
+ FreeRTOS_flush_logging( );
+ }
+ }
+ }
+ else
+ {
+ /* A sever situation: running out of segments for transmission.
+ No more data can be sent at the moment. */
+ if( lDone != 0 )
+ {
+ FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %ld bytes)\n", lBytesLeft ) );
+ }
+ break;
+ }
+ }
+
+ return lDone;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
+ {
+ return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments) );
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
+ {
+ uint32_t ulTxOutstanding;
+ BaseType_t xHasSpace;
+ TCPSegment_t *pxSegment;
+
+ /* This function will look if there is new transmission data. It will
+ return true if there is data to be sent. */
+
+ pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
+
+ if( pxSegment == NULL )
+ {
+ xHasSpace = pdFALSE;
+ }
+ else
+ {
+ /* How much data is outstanding, i.e. how much data has been sent
+ but not yet acknowledged ? */
+ if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber )
+ {
+ ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber;
+ }
+ else
+ {
+ ulTxOutstanding = 0UL;
+ }
+
+ /* Subtract this from the peer's space. */
+ ulWindowSize -= FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding );
+
+ /* See if the next segment may be sent. */
+ if( ulWindowSize >= ( uint32_t ) pxSegment->lDataLength )
+ {
+ xHasSpace = pdTRUE;
+ }
+ else
+ {
+ xHasSpace = pdFALSE;
+ }
+
+ /* If 'xHasSpace', it looks like the peer has at least space for 1
+ more new segment of size MSS. xSize.ulTxWindowLength is the self-imposed
+ limitation of the transmission window (in case of many resends it
+ may be decreased). */
+ if( ( ulTxOutstanding != 0UL ) && ( pxWindow->xSize.ulTxWindowLength < ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) )
+ {
+ xHasSpace = pdFALSE;
+ }
+ }
+
+ return xHasSpace;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
+ {
+ TCPSegment_t *pxSegment;
+ BaseType_t xReturn;
+ TickType_t ulAge, ulMaxAge;
+
+ *pulDelay = 0u;
+
+ if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE )
+ {
+ /* No need to look at retransmissions or new transmission as long as
+ there are priority segments. *pulDelay equals zero, meaning it must
+ be sent out immediately. */
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
+
+ if( pxSegment != NULL )
+ {
+ /* There is an outstanding segment, see if it is time to resend
+ it. */
+ ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer );
+
+ /* After a packet has been sent for the first time, it will wait
+ '1 * lSRTT' ms for an ACK. A second time it will wait '2 * lSRTT' ms,
+ each time doubling the time-out */
+ ulMaxAge = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
+
+ if( ulMaxAge > ulAge )
+ {
+ /* A segment must be sent after this amount of msecs */
+ *pulDelay = ulMaxAge - ulAge;
+ }
+
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ /* No priority segment, no outstanding data, see if there is new
+ transmission data. */
+ pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue );
+
+ /* See if it fits in the peer's reception window. */
+ if( pxSegment == NULL )
+ {
+ xReturn = pdFALSE;
+ }
+ else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
+ {
+ /* Too many outstanding messages. */
+ xReturn = pdFALSE;
+ }
+ else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
+ {
+ /* 'bSendFullSize' is a special optimisation. If true, the
+ driver will only sent completely filled packets (of MSS
+ bytes). */
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
+ {
+ TCPSegment_t *pxSegment;
+ uint32_t ulMaxTime;
+ uint32_t ulReturn = ~0UL;
+
+
+ /* Fetches data to be sent-out now.
+
+ Priority messages: segments with a resend need no check current sliding
+ window size. */
+ pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) );
+ pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber;
+
+ if( pxSegment == NULL )
+ {
+ /* Waiting messages: outstanding messages with a running timer
+ neither check peer's reception window size because these packets
+ have been sent earlier. */
+ pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) );
+
+ if( pxSegment != NULL )
+ {
+ /* Do check the timing. */
+ ulMaxTime = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
+
+ if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime )
+ {
+ /* A normal (non-fast) retransmission. Move it from the
+ head of the waiting queue. */
+ pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) );
+ pxSegment->u.bits.ucDupAckCount = pdFALSE_UNSIGNED;
+
+ /* Some detailed logging. */
+ if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) )
+ {
+ FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %ld bytes for sequence number %lu (%lX)\n",
+ pxWindow->usPeerPortNumber,
+ pxWindow->usOurPortNumber,
+ pxSegment->lDataLength,
+ pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ pxSegment->ulSequenceNumber ) );
+ FreeRTOS_flush_logging( );
+ }
+ }
+ else
+ {
+ pxSegment = NULL;
+ }
+ }
+
+ if( pxSegment == NULL )
+ {
+ /* New messages: sent-out for the first time. Check current
+ sliding window size of peer. */
+ pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) );
+
+ if( pxSegment == NULL )
+ {
+ /* No segments queued. */
+ ulReturn = 0UL;
+ }
+ else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) )
+ {
+ /* A segment has been queued but the driver waits until it
+ has a full size of MSS. */
+ ulReturn = 0;
+ }
+ else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
+ {
+ /* Peer has no more space at this moment. */
+ ulReturn = 0;
+ }
+ else
+ {
+ /* Move it out of the Tx queue. */
+ pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) );
+
+ /* Don't let pxHeadSegment point to this segment any more,
+ so no more data will be added. */
+ if( pxWindow->pxHeadSegment == pxSegment )
+ {
+ pxWindow->pxHeadSegment = NULL;
+ }
+
+ /* pxWindow->tx.highest registers the highest sequence
+ number in our transmission window. */
+ pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength );
+
+ /* ...and more detailed logging */
+ if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+ {
+ FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %ld bytes for sequence number %lu (ws %lu)\n",
+ pxWindow->usPeerPortNumber,
+ pxWindow->usOurPortNumber,
+ pxSegment->lDataLength,
+ pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ ulWindowSize ) );
+ FreeRTOS_flush_logging( );
+ }
+ }
+ }
+ }
+ else
+ {
+ /* There is a priority segment. It doesn't need any checking for
+ space or timeouts. */
+ if( xTCPWindowLoggingLevel != 0 )
+ {
+ FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %ld bytes for sequence number %lu (ws %lu)\n",
+ pxWindow->usPeerPortNumber,
+ pxWindow->usOurPortNumber,
+ pxSegment->lDataLength,
+ pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ ulWindowSize ) );
+ FreeRTOS_flush_logging( );
+ }
+ }
+
+ /* See if it has already been determined to return 0. */
+ if( ulReturn != 0UL )
+ {
+ configASSERT( listLIST_ITEM_CONTAINER( &(pxSegment->xQueueItem ) ) == NULL );
+
+ /* Now that the segment will be transmitted, add it to the tail of
+ the waiting queue. */
+ vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem );
+
+ /* And mark it as outstanding. */
+ pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
+
+ /* Administer the transmit count, needed for fast
+ retransmissions. */
+ ( pxSegment->u.bits.ucTransmitCount )++;
+
+ /* If there have been several retransmissions (4), decrease the
+ size of the transmission window to at most 2 times MSS. */
+ if( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW )
+ {
+ if( pxWindow->xSize.ulTxWindowLength > ( 2U * pxWindow->usMSS ) )
+ {
+ FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %d]: Change Tx window: %lu -> %u\n",
+ pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber,
+ pxWindow->xSize.ulTxWindowLength, 2 * pxWindow->usMSS ) );
+ pxWindow->xSize.ulTxWindowLength = ( 2UL * pxWindow->usMSS );
+ }
+ }
+
+ /* Clear the transmit timer. */
+ vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
+
+ pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
+
+ /* Inform the caller where to find the data within the queue. */
+ *plPosition = pxSegment->lStreamPos;
+
+ /* And return the length of the data segment */
+ ulReturn = ( uint32_t ) pxSegment->lDataLength;
+ }
+
+ return ulReturn;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
+ {
+ uint32_t ulBytesConfirmed = 0u;
+ uint32_t ulSequenceNumber = ulFirst, ulDataLength;
+ const ListItem_t *pxIterator;
+ const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xTxSegments );
+ BaseType_t xDoUnlink;
+ TCPSegment_t *pxSegment;
+ /* An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data
+ may be removed from the transmission queue(s).
+ All TX segments for which
+ ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a
+ contiguous block. Note that the segments are stored in xTxSegments in a
+ strict sequential order. */
+
+ /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT
+
+ 0 < a < 1; usually a = 1/8
+
+ RTO = 2 * SRTT
+
+ where:
+ RTT is Round Trip Time
+ SRTT is Smoothed RTT
+ RTO is Retransmit timeout
+
+ A Smoothed RTT will increase quickly, but it is conservative when
+ becoming smaller. */
+
+ for(
+ pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
+ ( pxIterator != ( const ListItem_t * ) pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 );
+ )
+ {
+ xDoUnlink = pdFALSE;
+ pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+
+ /* Move to the next item because the current item might get
+ removed. */
+ pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
+
+ /* Continue if this segment does not fall within the ACK'd range. */
+ if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE )
+ {
+ continue;
+ }
+
+ /* Is it ready? */
+ if( ulSequenceNumber != pxSegment->ulSequenceNumber )
+ {
+ break;
+ }
+
+ ulDataLength = ( uint32_t ) pxSegment->lDataLength;
+
+ if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED )
+ {
+ if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t )ulDataLength, ulLast ) != pdFALSE )
+ {
+ /* What happens? Only part of this segment was accepted,
+ probably due to WND limits
+
+ AAAAAAA BBBBBBB << acked
+ aaaaaaa aaaa << sent */
+ #if( ipconfigHAS_DEBUG_PRINTF != 0 )
+ {
+ uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber;
+ FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %lu - %lu Partial sequence number %lu - %lu\n",
+ pxWindow->usPeerPortNumber,
+ pxWindow->usOurPortNumber,
+ ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber,
+ ulLast - pxWindow->tx.ulFirstSequenceNumber,
+ ulFirstSeq, ulFirstSeq + ulDataLength ) );
+ }
+ #endif /* ipconfigHAS_DEBUG_PRINTF */
+ break;
+ }
+
+ /* This segment is fully ACK'd, set the flag. */
+ pxSegment->u.bits.bAcked = pdTRUE_UNSIGNED;
+
+ /* Calculate the RTT only if the segment was sent-out for the
+ first time and if this is the last ACK'd segment in a range. */
+ if( ( pxSegment->u.bits.ucTransmitCount == 1 ) && ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) )
+ {
+ int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) );
+
+ if( pxWindow->lSRTT >= mS )
+ {
+ /* RTT becomes smaller: adapt slowly. */
+ pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT );
+ }
+ else
+ {
+ /* RTT becomes larger: adapt quicker */
+ pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT );
+ }
+
+ /* Cap to the minimum of 50ms. */
+ if( pxWindow->lSRTT < winSRTT_CAP_mS )
+ {
+ pxWindow->lSRTT = winSRTT_CAP_mS;
+ }
+ }
+
+ /* Unlink it from the 3 queues, but do not destroy it (yet). */
+ xDoUnlink = pdTRUE;
+ }
+
+ /* pxSegment->u.bits.bAcked is now true. Is it located at the left
+ side of the transmission queue? If so, it may be freed. */
+ if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber )
+ {
+ if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+ {
+ FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %lu - %lu Ready sequence number %lu\n",
+ ulFirst - pxWindow->tx.ulFirstSequenceNumber,
+ ulLast - pxWindow->tx.ulFirstSequenceNumber,
+ pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
+ }
+
+ /* Increase the left-hand value of the transmission window. */
+ pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
+
+ /* This function will return the number of bytes that the tail
+ of txStream may be advanced. */
+ ulBytesConfirmed += ulDataLength;
+
+ /* All segments below tx.ulCurrentSequenceNumber may be freed. */
+ vTCPWindowFree( pxSegment );
+
+ /* No need to unlink it any more. */
+ xDoUnlink = pdFALSE;
+ }
+
+ if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) )
+ {
+ /* Remove item from its queues. */
+ uxListRemove( &pxSegment->xQueueItem );
+ }
+
+ ulSequenceNumber += ulDataLength;
+ }
+
+ return ulBytesConfirmed;
+ }
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst )
+ {
+ const ListItem_t *pxIterator;
+ const MiniListItem_t* pxEnd;
+ TCPSegment_t *pxSegment;
+ uint32_t ulCount = 0UL;
+
+ /* A higher Tx block has been acknowledged. Now iterate through the
+ xWaitQueue to find a possible condition for a FAST retransmission. */
+
+ pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &( pxWindow->xWaitQueue ) );
+
+ for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd );
+ pxIterator != ( const ListItem_t * ) pxEnd; )
+ {
+ /* Get the owner, which is a TCP segment. */
+ pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
+
+ /* Hop to the next item before the current gets unlinked. */
+ pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
+
+ /* Fast retransmission:
+ When 3 packets with a higher sequence number have been acknowledged
+ by the peer, it is very unlikely a current packet will ever arrive.
+ It will be retransmitted far before the RTO. */
+ if( ( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) &&
+ ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE ) &&
+ ( ++( pxSegment->u.bits.ucDupAckCount ) == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ) )
+ {
+ pxSegment->u.bits.ucTransmitCount = pdFALSE_UNSIGNED;
+
+ /* Not clearing 'ucDupAckCount' yet as more SACK's might come in
+ which might lead to a second fast rexmit. */
+ if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+ {
+ FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %lu < %lu\n",
+ pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ ulFirst - pxWindow->tx.ulFirstSequenceNumber ) );
+ FreeRTOS_flush_logging( );
+ }
+
+ /* Remove it from xWaitQueue. */
+ uxListRemove( &pxSegment->xQueueItem );
+
+ /* Add this segment to the priority queue so it gets
+ retransmitted immediately. */
+ vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) );
+ ulCount++;
+ }
+ }
+
+ return ulCount;
+ }
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
+ {
+ uint32_t ulFirstSequence, ulReturn;
+
+ /* Receive a normal ACK. */
+
+ ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber;
+
+ if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE )
+ {
+ ulReturn = 0UL;
+ }
+ else
+ {
+ ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber );
+ }
+
+ return ulReturn;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 1 )
+
+ uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast )
+ {
+ uint32_t ulAckCount = 0UL;
+ uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber;
+
+ /* Receive a SACK option. */
+ ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast );
+ prvTCPWindowFastRetransmit( pxWindow, ulFirst );
+
+ if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) )
+ {
+ FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %lu to %lu (ack = %lu)\n",
+ pxWindow->usPeerPortNumber,
+ pxWindow->usOurPortNumber,
+ ulFirst - pxWindow->tx.ulFirstSequenceNumber,
+ ulLast - pxWindow->tx.ulFirstSequenceNumber,
+ pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) );
+ FreeRTOS_flush_logging( );
+ }
+
+ return ulAckCount;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 1 */
+/*-----------------------------------------------------------*/
+
+/*
+##### # ##### #### ######
+# # # # # # # # # # #
+ # # # # # #
+ # ### ##### # # # # # #
+ # # # # # # # # #####
+ # # # # # # #### # # #
+ # # # # # # # # # #
+ # # # # #### # # # #
+ #### ##### # # # #### #### ####
+ #
+ ###
+*/
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+ int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace )
+ {
+ int32_t iReturn;
+
+ /* Data was received at 'ulSequenceNumber'. See if it was expected
+ and if there is enough space to store the new data. */
+ if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) )
+ {
+ iReturn = -1;
+ }
+ else
+ {
+ pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength;
+ iReturn = 0;
+ }
+
+ return iReturn;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+ int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax )
+ {
+ TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
+ int32_t lResult;
+
+ /* Data is being scheduled for transmission. */
+
+ /* lMax would indicate the size of the txStream. */
+ ( void ) lMax;
+ /* This is tiny TCP: there is only 1 segment for outgoing data.
+ As long as 'lDataLength' is unequal to zero, the segment is still occupied. */
+ if( pxSegment->lDataLength > 0 )
+ {
+ lResult = 0L;
+ }
+ else
+ {
+ if( ulLength > ( uint32_t ) pxSegment->lMaxLength )
+ {
+ if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+ {
+ FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %ld / %ld bytes\n", ulLength, pxSegment->lMaxLength ) );
+ }
+
+ ulLength = ( uint32_t ) pxSegment->lMaxLength;
+ }
+
+ if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+ {
+ FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %ld (%ld) Len %ld\n",
+ pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ ulLength ) );
+ }
+
+ /* The sequence number of the first byte in this packet. */
+ pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber;
+ pxSegment->lDataLength = ( int32_t ) ulLength;
+ pxSegment->lStreamPos = lPosition;
+ pxSegment->u.ulFlags = 0UL;
+ vTCPTimerSet( &( pxSegment->xTransmitTimer ) );
+
+ /* Increase the sequence number of the next data to be stored for
+ transmission. */
+ pxWindow->ulNextTxSequenceNumber += ulLength;
+ lResult = ( int32_t )ulLength;
+ }
+
+ return lResult;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+ uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition )
+ {
+ TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
+ uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength;
+ uint32_t ulMaxTime;
+
+ if( ulLength != 0UL )
+ {
+ /* _HT_ Still under investigation */
+ ( void ) ulWindowSize;
+
+ if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
+ {
+ /* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */
+ ulMaxTime = ( ( uint32_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
+
+ if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime )
+ {
+ ulLength = 0ul;
+ }
+ }
+
+ if( ulLength != 0ul )
+ {
+ pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED;
+ pxSegment->u.bits.ucTransmitCount++;
+ vTCPTimerSet (&pxSegment->xTransmitTimer);
+ pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber;
+ *plPosition = pxSegment->lStreamPos;
+ }
+ }
+
+ return ulLength;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+ BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow )
+ {
+ BaseType_t xReturn;
+
+ /* Has the outstanding data been sent because user wants to shutdown? */
+ if( pxWindow->xTxSegment.lDataLength == 0 )
+ {
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+ static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize );
+ static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize )
+ {
+ BaseType_t xReturn;
+
+ if( ulWindowSize >= pxWindow->usMSSInit )
+ {
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+ BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay )
+ {
+ TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
+ BaseType_t xReturn;
+ TickType_t ulAge, ulMaxAge;
+
+ /* Check data to be sent. */
+ *pulDelay = ( TickType_t ) 0;
+ if( pxSegment->lDataLength == 0 )
+ {
+ /* Got nothing to send right now. */
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED )
+ {
+ ulAge = ulTimerGetAge ( &pxSegment->xTransmitTimer );
+ ulMaxAge = ( ( TickType_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT );
+
+ if( ulMaxAge > ulAge )
+ {
+ *pulDelay = ulMaxAge - ulAge;
+ }
+
+ xReturn = pdTRUE;
+ }
+ else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE )
+ {
+ /* Too many outstanding messages. */
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+ uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber )
+ {
+ TCPSegment_t *pxSegment = &( pxWindow->xTxSegment );
+ uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength;
+
+ /* Receive a normal ACK */
+
+ if( ulDataLength != 0ul )
+ {
+ if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) )
+ {
+ if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE )
+ {
+ FreeRTOS_debug_printf( ( "win_tx_ack: acked %ld expc %ld len %ld\n",
+ ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ ulDataLength ) );
+ }
+
+ /* Nothing to send right now. */
+ ulDataLength = 0ul;
+ }
+ else
+ {
+ pxWindow->tx.ulCurrentSequenceNumber += ulDataLength;
+
+ if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) )
+ {
+ FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %ld len %ld\n",
+ ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber,
+ ulDataLength ) );
+ }
+
+ pxSegment->lDataLength = 0;
+ }
+ }
+
+ return ulDataLength;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+ BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow )
+ {
+ /* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber'
+ 'ulCurrentSequenceNumber' is the highest sequence number stored,
+ 'ulHighestSequenceNumber' is the highest sequence number seen. */
+ return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber );
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_TCP_WIN == 0 )
+
+ /* Destroy a window (always returns NULL) */
+ void vTCPWindowDestroy( TCPWindow_t *pxWindow )
+ {
+ /* As in tiny TCP there are no shared segments descriptors, there is
+ nothing to release. */
+ ( void ) pxWindow;
+ }
+
+#endif /* ipconfigUSE_TCP_WIN == 0 */
+/*-----------------------------------------------------------*/
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c
new file mode 100644
index 000000000..3595bbd81
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c
@@ -0,0 +1,420 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.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_UDP_IP.h"
+#include "FreeRTOS_ARP.h"
+#include "FreeRTOS_DHCP.h"
+#include "NetworkInterface.h"
+#include "NetworkBufferManagement.h"
+
+#if( ipconfigUSE_DNS == 1 )
+ #include "FreeRTOS_DNS.h"
+#endif
+
+/* The expected IP version and header length coded into the IP header itself. */
+#define ipIP_VERSION_AND_HEADER_LENGTH_BYTE ( ( uint8_t ) 0x45 )
+
+/* Part of the Ethernet and IP headers are always constant when sending an IPv4
+UDP packet. This array defines the constant parts, allowing this part of the
+packet to be filled in using a simple memcpy() instead of individual writes. */
+UDPPacketHeader_t xDefaultPartUDPPacketHeader =
+{
+ /* .ucBytes : */
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source MAC address. */
+ 0x08, 0x00, /* Ethernet frame type. */
+ ipIP_VERSION_AND_HEADER_LENGTH_BYTE, /* ucVersionHeaderLength. */
+ 0x00, /* ucDifferentiatedServicesCode. */
+ 0x00, 0x00, /* usLength. */
+ 0x00, 0x00, /* usIdentification. */
+ 0x00, 0x00, /* usFragmentOffset. */
+ ipconfigUDP_TIME_TO_LIVE, /* ucTimeToLive */
+ ipPROTOCOL_UDP, /* ucProtocol. */
+ 0x00, 0x00, /* usHeaderChecksum. */
+ 0x00, 0x00, 0x00, 0x00 /* Source IP address. */
+ }
+};
+/*-----------------------------------------------------------*/
+
+void vProcessGeneratedUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
+{
+UDPPacket_t *pxUDPPacket;
+IPHeader_t *pxIPHeader;
+eARPLookupResult_t eReturned;
+uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress;
+
+ /* Map the UDP packet onto the start of the frame. */
+ pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
+
+ /* Determine the ARP cache status for the requested IP address. */
+ eReturned = eARPGetCacheEntry( &( ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) );
+
+ if( eReturned != eCantSendPacket )
+ {
+ if( eReturned == eARPCacheHit )
+ {
+ #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
+ uint8_t ucSocketOptions;
+ #endif
+ iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );
+
+ /* Create short cuts to the data within the packet. */
+ pxIPHeader = &( pxUDPPacket->xIPHeader );
+
+ #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
+ /* Is it possible that the packet is not actually a UDP packet
+ after all, but an ICMP packet. */
+ if( pxNetworkBuffer->usPort != ipPACKET_CONTAINS_ICMP_DATA )
+ #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
+ {
+ UDPHeader_t *pxUDPHeader;
+
+ pxUDPHeader = &( pxUDPPacket->xUDPHeader );
+
+ pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort;
+ pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort;
+ pxUDPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) );
+ pxUDPHeader->usLength = FreeRTOS_htons( pxUDPHeader->usLength );
+ pxUDPHeader->usChecksum = 0u;
+ }
+
+ /* memcpy() the constant parts of the header information into
+ the correct location within the packet. This fills in:
+ xEthernetHeader.xSourceAddress
+ xEthernetHeader.usFrameType
+ xIPHeader.ucVersionHeaderLength
+ xIPHeader.ucDifferentiatedServicesCode
+ xIPHeader.usLength
+ xIPHeader.usIdentification
+ xIPHeader.usFragmentOffset
+ xIPHeader.ucTimeToLive
+ xIPHeader.ucProtocol
+ and
+ xIPHeader.usHeaderChecksum
+ */
+
+ /* Save options now, as they will be overwritten by memcpy */
+ #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
+ {
+ ucSocketOptions = pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ];
+ }
+ #endif
+
+ memcpy( ( void *) &( pxUDPPacket->xEthernetHeader.xSourceAddress ), ( void * ) xDefaultPartUDPPacketHeader.ucBytes, sizeof( xDefaultPartUDPPacketHeader ) );
+
+ #if ipconfigSUPPORT_OUTGOING_PINGS == 1
+ if( pxNetworkBuffer->usPort == ipPACKET_CONTAINS_ICMP_DATA )
+ {
+ pxIPHeader->ucProtocol = ipPROTOCOL_ICMP;
+ pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( IPHeader_t ) );
+ }
+ else
+ #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
+ {
+ pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( IPHeader_t ) + sizeof( UDPHeader_t ) );
+ }
+
+ /* The total transmit size adds on the Ethernet header. */
+ pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( EthernetHeader_t );
+ pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );
+ pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
+
+ #if( ipconfigUSE_LLMNR == 1 )
+ {
+ /* LLMNR messages are typically used on a LAN and they're
+ * not supposed to cross routers */
+ if( pxNetworkBuffer->ulIPAddress == ipLLMNR_IP_ADDR )
+ {
+ pxIPHeader->ucTimeToLive = 0x01;
+ }
+ }
+ #endif
+
+ #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
+ {
+ pxIPHeader->usHeaderChecksum = 0u;
+ pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
+ pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
+
+ if( ( ucSocketOptions & ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT ) != 0u )
+ {
+ usGenerateProtocolChecksum( (uint8_t*)pxUDPPacket, pdTRUE );
+ }
+ else
+ {
+ pxUDPPacket->xUDPHeader.usChecksum = 0u;
+ }
+ }
+ #endif
+ }
+ else if( eReturned == eARPCacheMiss )
+ {
+ /* Add an entry to the ARP table with a null hardware address.
+ This allows the ARP timer to know that an ARP reply is
+ outstanding, and perform retransmissions if necessary. */
+ vARPRefreshCacheEntry( NULL, ulIPAddress );
+
+ /* Generate an ARP for the required IP address. */
+ iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );
+ pxNetworkBuffer->ulIPAddress = ulIPAddress;
+ vARPGenerateRequestPacket( pxNetworkBuffer );
+ }
+ else
+ {
+ /* The lookup indicated that an ARP request has already been
+ sent out for the queried IP address. */
+ eReturned = eCantSendPacket;
+ }
+ }
+
+ if( eReturned != eCantSendPacket )
+ {
+ /* The network driver is responsible for freeing the network buffer
+ after the packet has been sent. */
+
+ #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+ {
+ if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+ {
+ BaseType_t xIndex;
+
+ 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
+
+ xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
+ }
+ else
+ {
+ /* The packet can't be sent (DHCP not completed?). Just drop the
+ packet. */
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ }
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort )
+{
+BaseType_t xReturn = pdPASS;
+FreeRTOS_Socket_t *pxSocket;
+
+UDPPacket_t *pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer;
+
+ pxSocket = pxUDPSocketLookup( usPort );
+
+ if( pxSocket )
+ {
+
+ /* When refreshing the ARP cache with received UDP packets we must be
+ careful; hundreds of broadcast messages may pass and if we're not
+ handling them, no use to fill the ARP cache with those IP addresses. */
+ vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
+
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ {
+ /* Did the owner of this socket register a reception handler ? */
+ if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleReceive ) )
+ {
+ struct freertos_sockaddr xSourceAddress, destinationAddress;
+ void *pcData = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
+ FOnUDPReceive_t xHandler = ( FOnUDPReceive_t ) pxSocket->u.xUDP.pxHandleReceive;
+ xSourceAddress.sin_port = pxNetworkBuffer->usPort;
+ xSourceAddress.sin_addr = pxNetworkBuffer->ulIPAddress;
+ destinationAddress.sin_port = usPort;
+ destinationAddress.sin_addr = pxUDPPacket->xIPHeader.ulDestinationIPAddress;
+
+ if( xHandler( ( Socket_t * ) pxSocket, ( void* ) pcData, ( size_t ) pxNetworkBuffer->xDataLength,
+ &xSourceAddress, &destinationAddress ) != pdFALSE )
+ {
+ xReturn = pdFAIL; /* xHandler has consumed the data, do not add it to .xWaitingPacketsList'. */
+ }
+ }
+ }
+ #endif /* ipconfigUSE_CALLBACKS */
+
+ #if( ipconfigUDP_MAX_RX_PACKETS > 0 )
+ {
+ if( xReturn == pdPASS )
+ {
+ if ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) >= pxSocket->u.xUDP.uxMaxPackets )
+ {
+ FreeRTOS_debug_printf( ( "xProcessReceivedUDPPacket: buffer full %ld >= %ld port %u\n",
+ listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ),
+ pxSocket->u.xUDP.uxMaxPackets, pxSocket->usLocalPort ) );
+ xReturn = pdFAIL; /* we did not consume or release the buffer */
+ }
+ }
+ }
+ #endif
+
+ if( xReturn == pdPASS )
+ {
+ vTaskSuspendAll();
+ {
+ if( xReturn == pdPASS )
+ {
+ taskENTER_CRITICAL();
+ {
+ /* Add the network packet to the list of packets to be
+ processed by the socket. */
+ vListInsertEnd( &( pxSocket->u.xUDP.xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
+ }
+ taskEXIT_CRITICAL();
+ }
+ }
+ xTaskResumeAll();
+
+ /* Set the socket's receive event */
+ if( pxSocket->xEventGroup != NULL )
+ {
+ xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_RECEIVE );
+ }
+
+ #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+ {
+ if( ( pxSocket->pxSocketSet != NULL ) && ( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) )
+ {
+ xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, eSELECT_READ );
+ }
+ }
+ #endif
+
+ #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
+ {
+ if( pxSocket->pxUserSemaphore != NULL )
+ {
+ xSemaphoreGive( pxSocket->pxUserSemaphore );
+ }
+ }
+ #endif
+
+ #if( ipconfigUSE_DHCP == 1 )
+ {
+ if( xIsDHCPSocket( pxSocket ) )
+ {
+ xSendEventToIPTask( eDHCPEvent );
+ }
+ }
+ #endif
+ }
+ }
+ else
+ {
+ /* There is no socket listening to the target port, but still it might
+ be for this node. */
+
+ #if( ipconfigUSE_DNS == 1 )
+ /* A DNS reply, check for the source port. Although the DNS client
+ does open a UDP socket to send a messages, this socket will be
+ closed after a short timeout. Messages that come late (after the
+ socket is closed) will be treated here. */
+ if( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usSourcePort ) == ipDNS_PORT )
+ {
+ vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
+ xReturn = ( BaseType_t )ulDNSHandlePacket( pxNetworkBuffer );
+ }
+ else
+ #endif
+
+ #if( ipconfigUSE_LLMNR == 1 )
+ /* A LLMNR request, check for the destination port. */
+ if( ( usPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) ||
+ ( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) )
+ {
+ vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
+ xReturn = ( BaseType_t )ulDNSHandlePacket( pxNetworkBuffer );
+ }
+ else
+ #endif /* ipconfigUSE_LLMNR */
+
+ #if( ipconfigUSE_NBNS == 1 )
+ /* a NetBIOS request, check for the destination port */
+ if( ( usPort == FreeRTOS_ntohs( ipNBNS_PORT ) ) ||
+ ( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipNBNS_PORT ) ) )
+ {
+ vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
+ xReturn = ( BaseType_t )ulNBNSHandlePacket( pxNetworkBuffer );
+ }
+ else
+ #endif /* ipconfigUSE_NBNS */
+ {
+ xReturn = pdFAIL;
+ }
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt
new file mode 100644
index 000000000..57125a547
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt
@@ -0,0 +1,131 @@
+Changes since the 160112 release
+
+FTP : now has ipconfigFTP_HAS_USER_PROPERTIES_HOOK
+Each user can be assigned a different root directory and different access rights.
+Read-only access for FTP is now possible.
+
+Adapted to comply a bit more to MISRA rules.
+The introduction of unsigned true/false, e.g. pdTRUE_UNSIGNED.
+
+'ipBUFFER_PADDING' now configurable (expert option).
+
+Added ipconfigFTP_HAS_USER_PROPERTIES_HOOK.
+ipconfigHAS_TX_CRC_OFFLOADING
+Improve support for read only file systems in the FTP server.
+
+Depending on priorities: FreeRTOS_accept() could fail if the priority of the application task is higher than the priority of the IP-task. Now with a higher priority FreeRTOS_accept() will still work correctly.
+
+Depending on the tick rate: A TCP socket could freeze (stop working) when the FreeRTOS tick rate was lower than 1,000 Hz. Now also tested with 100 Hz.
+
+When "ipconfigZERO_COPY_TX_DRIVER = 0", sometime xNetworkInterfaceOutput() was called to send out a small TCP ACK. The network buffer would refer to space on the TCP socket ("lastPacket"), which was not 8-byte aligned. Repaired: from now on the buffer will have a proper 8-byte alignment.
+
+"#if __cplusplus" is been replaced with the more proper test "#ifdef __cplusplus".
+
+
+
+These are the recent commits:
+565 Initial check-in of +TCP/multi
+566 LPC18xx : updated and re-tested the TCP and FAT drivers
+569 +TCP : protocols: Added an installable application hook: "CheckDrivesHook"
+570 +TCP : will now work properly when configTICK_RATE_HZ < 1000
+571 +TCP : will now work properly when configTICK_RATE_HZ < 1000
+572 +TCP : FreeRTOS_recvfrom now recognises "FREERTOS_MSG_PEEK"
+573 +FAT : Zynq : writing may fail if it goes too fast. Introduced pauses but not yet satisfied
+
+
+Changes between 160112 and 160111 releases
+
+ + Updated the STM32 network driver so checksums are calculated by the
+ hardware.
+ + Implemented a simple "quit" command in the TCP command console.
+
+Changes between 150825 and 160111 releases
+
+ + New device support: Demo applications and example drivers are provided
+ for Atmel SAM4E and ST STM32F4 microcontrollers.
+ + Various updates to improve compliance with the FreeRTOS coding standard.
+ + Added a command console example that uses TCP/IP for input and output (the
+ pre-existing command console example uses UDP/IP).
+ + Updated the UDP logging example so it will send log messages to the local
+ UDP broadcast address if a specific IP address is not provided. This
+ simplifies configuration, but note not all switches and routers will pass
+ broadcast messages.
+ + Add TCP echo client and TCP echo server examples to the Zynq demo.
+ + Minor updates to the Zynq network driver.
+ + Update the Zynq project to use version 2015.4 of the Xilinx SDK.
+ + Introduce FreeRTOS_SignalSocket(), which can be used to interrupt a task
+ that is blocked while reading from a socket ( FreeRTOS_recv[from] ).
+ + Make use of FreeRTOS_SignalSocket() in the FTP and HTTP servers.
+ + Major updates to the NTP client, although this is not included in any of
+ the pre-configured demo applications yet.
+ + Added support for DHCP zero pad option.
+ + Added uxGetMinimumIPQueueSpace(), a function to monitor the minimum amount
+ of space on the message queue.
+ + Better handling of zero length files in the FTP server.
+ + Fixed a bug reported by Andrey Ivanov from swissEmbedded that affects
+ users of 'ipconfigZERO_COPY_TX_DRIVER'.
+
+
+Changes between 150825 150825 (?)
+
+ + Added xApplicationDHCPUserHook() so a user defined hook will be
+ called at certain points in the DHCP process if
+ ipconfigDHCP_USES_USER_HOOK is set to 1.
+ + Added FreeRTOS_get_tx_head() to improve TCP zero copy behaviour - for
+ expert use only.
+ + RST is no longer sent if only the ACK flag is set.
+ + Previously, an immediate ACK was only sent when buffer space was
+ exhausted. Now, to improve performance, it is possible to send an
+ immediate ACK earlier - dependent on the ipconfigTCP_ACK_EARLIER_PACKET
+ setting.
+ + LLMNR and NBNS requests can now be sent to locate other devices -
+ previously these protocols would only be replied to, not generated.
+ + Added Auto-IP functionality (still in test) in case DHCP fails. Dependent
+ on the ipconfigDHCP_FALL_BACK_LINK_LAYER_ADDRESS and
+ ipconfigARP_USE_CLASH_DETECTION settings.
+ + Added NTP code and demo.
+ + FTP can now STOR and RETR zero-length files.
+ + Added LLMNR demo to Win32 demo - so now the Win32 responds to
+ "ping RTOSDemo".
+
+Changes between 141019 and 150825
+
+ + Added FTP server, which uses the new FreeRTOS+FAT component.
+ + Added basic HTTP server, which uses the new FreeRTOS+FAT component.
+ + Multiple definitions that are now common with FreeRTOS+FAT have been moved
+ into FreeRTOS's ProjDefs.h header file, and so prefixed with 'pd'.
+ + Introduced ipconfigZERO_COPY_TX_DRIVER, which defines who is responsible
+ for freeing a buffer sent to to the MAC driver for transmission, and
+ facilitates the development of zero copy drivers.
+ + Introduced the FREERTOS_MSG_DONTWAIT flag. The flag can be used as a
+ simpler and faster alternative to using FreeRTOS_setsockopt() to set the
+ send or receive timeout to 0.
+ + A few functions that were previously all lower case are now mixed case, as
+ lower case function names are only used when they are equivalent to a
+ a Berkeley sockets API function of the same name.
+ + Introduced uxGetMinimumFreeNetworkBuffers() to return the minimum number
+ of network buffers that have ever existed since the application started
+ executing.
+ + Introduce ipconfigETHERNET_MINIMUM_PACKET_BYTES to allow the application
+ writer to set their own minimum buffer size should the hardware not be
+ capable of padding under-sized Ethernet frames.
+ + vNetworkBufferRelease() renamed vReleaseNetworkBuffer() - just for
+ consistency with the names of other functions in the same file.
+ + Grouped DHCP status data into a structure.
+ + DHCP is now tried both with and without the broadcast flag.
+ + Replaced occurrences of configASSERT_VOID() with configASSERT().
+ + ipconfigDNS_USE_CALLBACKS introduced to allow FreeRTOS_gethostbyname() to
+ be used without blocking.
+ + Fix: LLMNR and NBNS behaviour when the reply is in a larger buffer than the
+ request, and BufferAllocation_2 was used.
+ + Introduced ipMAX_IP_TASK_SLEEP_TIME to allow the application writer to
+ override the default value of 10 seconds.
+ + Fix: Correct error in *pxUDPPayloadBuffer_to_NetworkBuffer().
+ + FreeRTOS_recv() now recognises the FREERTOS_ZERO_COPY flag, which, when
+ set, the void *pvBuffer parameter is interpreted as void **pvBuffer.
+ + FreeRTOS_listen() now returns an error code. Previously it always
+ returned 0.
+ + Fix: Previously if a listening socket was reused, and a connection
+ failed, the TCP/IP stack closed the socket, now the socket is correctly
+ left unclosed as it is owned by the application.
+ + Various other formatting and minor fix alterations. \ No newline at end of file
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/ReadMe.url b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/ReadMe.url
new file mode 100644
index 000000000..8a8017f6b
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/ReadMe.url
@@ -0,0 +1,5 @@
+[{000214A0-0000-0000-C000-000000000046}]
+Prop3=19,2
+[InternetShortcut]
+URL=http://www.freertos.org/tcp
+IDList=
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h
new file mode 100644
index 000000000..79af0740c
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h
@@ -0,0 +1,577 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef FREERTOS_DEFAULT_IP_CONFIG_H
+#define FREERTOS_DEFAULT_IP_CONFIG_H
+
+/* The error numbers defined in this file will be moved to the core FreeRTOS
+code in future versions of FreeRTOS - at which time the following header file
+will be removed. */
+#include "FreeRTOS_errno_TCP.h"
+
+/* This file provides default values for configuration options that are missing
+from the FreeRTOSIPConfig.h configuration header file. */
+
+
+/* Ensure defined configuration constants are using the most up to date naming. */
+#ifdef tcpconfigIP_TIME_TO_LIVE
+ #error now called: ipconfigTCP_TIME_TO_LIVE
+#endif
+
+#ifdef updconfigIP_TIME_TO_LIVE
+ #error now called: ipconfigUDP_TIME_TO_LIVE
+#endif
+
+#ifdef ipFILLER_SIZE
+ #error now called: ipconfigPACKET_FILLER_SIZE
+#endif
+
+#ifdef dnsMAX_REQUEST_ATTEMPTS
+ #error now called: ipconfigDNS_REQUEST_ATTEMPTS
+#endif
+
+#ifdef ipconfigUDP_TASK_PRIORITY
+ #error now called: ipconfigIP_TASK_PRIORITY
+#endif
+
+#ifdef ipconfigUDP_TASK_STACK_SIZE_WORDS
+ #error now called: ipconfigIP_TASK_STACK_SIZE_WORDS
+#endif
+
+#ifdef ipconfigDRIVER_INCLUDED_RX_IP_FILTERING
+ #error now called: ipconfigETHERNET_DRIVER_FILTERS_PACKETS
+#endif
+
+#ifdef ipconfigMAX_SEND_BLOCK_TIME_TICKS
+ #error now called: ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS
+#endif
+
+#ifdef ipconfigUSE_RECEIVE_CONNECT_CALLBACKS
+ #error now called: ipconfigUSE_CALLBACKS
+#endif
+
+#ifdef ipconfigNUM_NETWORK_BUFFERS
+ #error now called: ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS
+#endif
+
+#ifdef ipconfigTCP_HANG_PROT
+ #error now called: ipconfigTCP_HANG_PROTECTION
+#endif
+
+#ifdef ipconfigTCP_HANG_PROT_TIME
+ #error now called: ipconfigTCP_HANG_PROTECTION_TIME
+#endif
+
+#ifdef FreeRTOS_lprintf
+ #error now called: FreeRTOS_debug_printf
+#endif
+
+#if ( ipconfigEVENT_QUEUE_LENGTH < ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) )
+ #error The ipconfigEVENT_QUEUE_LENGTH parameter must be at least ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5
+#endif
+
+#if ( ipconfigNETWORK_MTU < 46 )
+ #error ipconfigNETWORK_MTU must be at least 46.
+#endif
+
+#ifdef ipconfigBUFFER_ALLOC_FIXED_SIZE
+ #error ipconfigBUFFER_ALLOC_FIXED_SIZE was dropped and replaced by a const value, declared in BufferAllocation[12].c
+#endif
+
+#ifdef ipconfigNIC_SEND_PASSES_DMA
+ #error now called: ipconfigZERO_COPY_TX_DRIVER
+#endif
+
+#ifdef HAS_TX_CRC_OFFLOADING
+ /* _HT_ As these macro names have changed, throw an error
+ if they're still defined. */
+ #error now called: ipconfigHAS_TX_CRC_OFFLOADING
+#endif
+
+#ifdef HAS_RX_CRC_OFFLOADING
+ #error now called: ipconfigHAS_RX_CRC_OFFLOADING
+#endif
+
+#ifdef ipconfigTCP_RX_BUF_LEN
+ #error ipconfigTCP_RX_BUF_LEN is now called ipconfigTCP_RX_BUFFER_LENGTH
+#endif
+
+#ifdef ipconfigTCP_TX_BUF_LEN
+ #error ipconfigTCP_TX_BUF_LEN is now called ipconfigTCP_TX_BUFFER_LENGTH
+#endif
+
+#ifdef ipconfigDHCP_USES_USER_HOOK
+ #error ipconfigDHCP_USES_USER_HOOK and its associated callback have been superceeded - see http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html#ipconfigUSE_DHCP_HOOK
+#endif
+
+#ifndef ipconfigUSE_TCP
+ #define ipconfigUSE_TCP ( 1 )
+#endif
+
+#if ipconfigUSE_TCP
+
+ /* Include support for TCP scaling windows */
+ #ifndef ipconfigUSE_TCP_WIN
+ #define ipconfigUSE_TCP_WIN ( 1 )
+ #endif
+
+ #ifndef ipconfigTCP_WIN_SEG_COUNT
+ #define ipconfigTCP_WIN_SEG_COUNT ( 256 )
+ #endif
+
+ #ifndef ipconfigIGNORE_UNKNOWN_PACKETS
+ /* When non-zero, TCP will not send RST packets in reply to
+ TCP packets which are unknown, or out-of-order. */
+ #define ipconfigIGNORE_UNKNOWN_PACKETS ( 0 )
+ #endif
+#endif
+
+/*
+ * For debuging/logging: check if the port number is used for telnet
+ * Some events will not be logged for telnet connections
+ * because it would produce logging about the transmission of the logging...
+ * This macro will only be used if FreeRTOS_debug_printf() is defined for logging
+ */
+#ifndef ipconfigTCP_MAY_LOG_PORT
+ #define ipconfigTCP_MAY_LOG_PORT(xPort) ( ( xPort ) != 23u )
+#endif
+
+
+#ifndef ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME
+ #define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME portMAX_DELAY
+#endif
+
+#ifndef ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME
+ #define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME portMAX_DELAY
+#endif
+
+/*
+ * FreeRTOS debug logging routine (proposal)
+ * The macro will be called in the printf() style. Users can define
+ * their own logging routine as:
+ *
+ * #define FreeRTOS_debug_printf( MSG ) my_printf MSG
+ *
+ * The FreeRTOS_debug_printf() must be thread-safe but does not have to be
+ * interrupt-safe.
+ */
+#ifdef ipconfigHAS_DEBUG_PRINTF
+ #if( ipconfigHAS_DEBUG_PRINTF == 0 )
+ #ifdef FreeRTOS_debug_printf
+ #error Do not define FreeRTOS_debug_print if ipconfigHAS_DEBUG_PRINTF is set to 0
+ #endif /* ifdef FreeRTOS_debug_printf */
+ #endif /* ( ipconfigHAS_DEBUG_PRINTF == 0 ) */
+#endif /* ifdef ipconfigHAS_DEBUG_PRINTF */
+
+#ifndef FreeRTOS_debug_printf
+ #define FreeRTOS_debug_printf( MSG ) do{} while(0)
+ #define ipconfigHAS_DEBUG_PRINTF 0
+#endif
+
+/*
+ * FreeRTOS general logging routine (proposal)
+ * Used in some utility functions such as FreeRTOS_netstat() and FreeRTOS_PrintARPCache()
+ *
+ * #define FreeRTOS_printf( MSG ) my_printf MSG
+ *
+ * The FreeRTOS_printf() must be thread-safe but does not have to be interrupt-safe
+ */
+#ifdef ipconfigHAS_PRINTF
+ #if( ipconfigHAS_PRINTF == 0 )
+ #ifdef FreeRTOS_printf
+ #error Do not define FreeRTOS_print if ipconfigHAS_PRINTF is set to 0
+ #endif /* ifdef FreeRTOS_debug_printf */
+ #endif /* ( ipconfigHAS_PRINTF == 0 ) */
+#endif /* ifdef ipconfigHAS_PRINTF */
+
+#ifndef FreeRTOS_printf
+ #define FreeRTOS_printf( MSG ) do{} while(0)
+ #define ipconfigHAS_PRINTF 0
+#endif
+
+/*
+ * In cases where a lot of logging is produced, FreeRTOS_flush_logging( )
+ * will be called to give the logging module a chance to flush the data
+ * An example of this is the netstat command, which produces many lines of logging
+ */
+#ifndef FreeRTOS_flush_logging
+ #define FreeRTOS_flush_logging( ) do{} while(0)
+#endif
+
+/* Malloc functions. Within most applications of FreeRTOS, the couple
+ * pvPortMalloc()/vPortFree() will be used.
+ * If there is also SDRAM, the user may decide to use a different memory
+ * allocator:
+ * MallocLarge is used to allocate large TCP buffers (for Rx/Tx)
+ * MallocSocket is used to allocate the space for the sockets
+ */
+#ifndef pvPortMallocLarge
+ #define pvPortMallocLarge( x ) pvPortMalloc( x )
+#endif
+
+#ifndef vPortFreeLarge
+ #define vPortFreeLarge(ptr) vPortFree(ptr)
+#endif
+
+#ifndef pvPortMallocSocket
+ #define pvPortMallocSocket( x ) pvPortMalloc( x )
+#endif
+
+#ifndef vPortFreeSocket
+ #define vPortFreeSocket(ptr) vPortFree(ptr)
+#endif
+
+/*
+ * At several places within the library, random numbers are needed:
+ * - DHCP: For creating a DHCP transaction number
+ * - TCP: Set the Initial Sequence Number: this is the value of the first outgoing
+ * sequence number being used when connecting to a peer.
+ * Having a well randomised ISN is important to avoid spoofing
+ * - UDP/TCP: for setting the first port number to be used, in case a socket
+ * uses a 'random' or anonymous port number
+ */
+#ifndef ipconfigRAND32
+ #define ipconfigRAND32() rand()
+#endif
+/* --------------------------------------------------------
+ * End of: HT Added some macro defaults for the PLUS-UDP project
+ * -------------------------------------------------------- */
+
+#ifndef ipconfigUSE_NETWORK_EVENT_HOOK
+ #define ipconfigUSE_NETWORK_EVENT_HOOK 0
+#endif
+
+#ifndef ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS
+ #define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( pdMS_TO_TICKS( 20 ) )
+#endif
+
+#ifndef ipconfigARP_CACHE_ENTRIES
+ #define ipconfigARP_CACHE_ENTRIES 10
+#endif
+
+#ifndef ipconfigMAX_ARP_RETRANSMISSIONS
+ #define ipconfigMAX_ARP_RETRANSMISSIONS ( 5u )
+#endif
+
+#ifndef ipconfigMAX_ARP_AGE
+ #define ipconfigMAX_ARP_AGE 150u
+#endif
+
+#ifndef ipconfigUSE_ARP_REVERSED_LOOKUP
+ #define ipconfigUSE_ARP_REVERSED_LOOKUP 0
+#endif
+
+#ifndef ipconfigUSE_ARP_REMOVE_ENTRY
+ #define ipconfigUSE_ARP_REMOVE_ENTRY 0
+#endif
+
+#ifndef ipconfigINCLUDE_FULL_INET_ADDR
+ #define ipconfigINCLUDE_FULL_INET_ADDR 1
+#endif
+
+#ifndef ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS
+ #define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 45
+#endif
+
+#ifndef ipconfigEVENT_QUEUE_LENGTH
+ #define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 )
+#endif
+
+#ifndef ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND
+ #define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1
+#endif
+
+#ifndef ipconfigUDP_TIME_TO_LIVE
+ #define ipconfigUDP_TIME_TO_LIVE 128
+#endif
+
+#ifndef ipconfigTCP_TIME_TO_LIVE
+ #define ipconfigTCP_TIME_TO_LIVE 128
+#endif
+
+#ifndef ipconfigUDP_MAX_RX_PACKETS
+ /* Make postive to define the maximum number of packets which will be buffered
+ * for each UDP socket.
+ * Can be overridden with the socket option FREERTOS_SO_UDP_MAX_RX_PACKETS
+ */
+ #define ipconfigUDP_MAX_RX_PACKETS 0u
+#endif
+
+#ifndef ipconfigUSE_DHCP
+ #define ipconfigUSE_DHCP 1
+#endif
+
+#ifndef ipconfigUSE_DHCP_HOOK
+ #define ipconfigUSE_DHCP_HOOK 0
+#endif
+
+#ifndef ipconfigDHCP_FALL_BACK_AUTO_IP
+ /*
+ * Only applicable when DHCP is in use:
+ * If no DHCP server responds, use "Auto-IP" : the
+ * device will allocate a random LinkLayer IP address.
+ */
+ #define ipconfigDHCP_FALL_BACK_AUTO_IP ( 0 )
+#endif
+
+#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+ #define ipconfigARP_USE_CLASH_DETECTION 1
+#endif
+
+#ifndef ipconfigARP_USE_CLASH_DETECTION
+ #define ipconfigARP_USE_CLASH_DETECTION 0
+#endif
+
+#ifndef ipconfigNETWORK_MTU
+ #define ipconfigNETWORK_MTU 1500
+#endif
+
+#ifndef ipconfigTCP_MSS
+ #define ipconfigTCP_MSS ( ipconfigNETWORK_MTU - ipSIZE_OF_IPv4_HEADER - ipSIZE_OF_TCP_HEADER )
+#endif
+
+/* Each TCP socket has circular stream buffers for Rx and Tx, which
+ * have a fixed maximum size.
+ * The defaults for these size are defined here, although
+ * they can be overridden at runtime by using the setsockopt() call */
+#ifndef ipconfigTCP_RX_BUFFER_LENGTH
+ #define ipconfigTCP_RX_BUFFER_LENGTH ( 4u * ipconfigTCP_MSS ) /* defaults to 5840 bytes */
+#endif
+
+/* Define the size of Tx stream buffer for TCP sockets */
+#ifndef ipconfigTCP_TX_BUFFER_LENGTH
+# define ipconfigTCP_TX_BUFFER_LENGTH ( 4u * ipconfigTCP_MSS ) /* defaults to 5840 bytes */
+#endif
+
+#ifndef ipconfigMAXIMUM_DISCOVER_TX_PERIOD
+ #ifdef _WINDOWS_
+ #define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( pdMS_TO_TICKS( 999 ) )
+ #else
+ #define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( pdMS_TO_TICKS( 30000 ) )
+ #endif /* _WINDOWS_ */
+#endif /* ipconfigMAXIMUM_DISCOVER_TX_PERIOD */
+
+#ifndef ipconfigUSE_DNS
+ #define ipconfigUSE_DNS 1
+#endif
+
+#ifndef ipconfigDNS_REQUEST_ATTEMPTS
+ #define ipconfigDNS_REQUEST_ATTEMPTS 5
+#endif
+
+#ifndef ipconfigUSE_DNS_CACHE
+ #define ipconfigUSE_DNS_CACHE 0
+#endif
+
+#if( ipconfigUSE_DNS_CACHE != 0 )
+ #ifndef ipconfigDNS_CACHE_NAME_LENGTH
+ #define ipconfigDNS_CACHE_NAME_LENGTH ( 16 )
+ #endif
+
+ #ifndef ipconfigDNS_CACHE_ENTRIES
+ #define ipconfigDNS_CACHE_ENTRIES 0
+ #endif
+#endif /* ipconfigUSE_DNS_CACHE != 0 */
+
+#ifndef ipconfigCHECK_IP_QUEUE_SPACE
+ #define ipconfigCHECK_IP_QUEUE_SPACE 0
+#endif
+
+#ifndef ipconfigUSE_LLMNR
+ /* Include support for LLMNR: Link-local Multicast Name Resolution (non-Microsoft) */
+ #define ipconfigUSE_LLMNR ( 0 )
+#endif
+
+#if( !defined( ipconfigUSE_DNS ) )
+ #if( ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) )
+ /* LLMNR and NBNS depend on DNS because those protocols share a lot of code. */
+ #error When either LLMNR or NBNS is used, ipconfigUSE_DNS must be defined
+ #endif
+#endif
+
+#ifndef ipconfigREPLY_TO_INCOMING_PINGS
+ #define ipconfigREPLY_TO_INCOMING_PINGS 1
+#endif
+
+#ifndef ipconfigSUPPORT_OUTGOING_PINGS
+ #define ipconfigSUPPORT_OUTGOING_PINGS 0
+#endif
+
+#ifndef ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES
+ #define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1
+#endif
+
+#ifndef ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES
+ #define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1
+#endif
+
+#ifndef configINCLUDE_TRACE_RELATED_CLI_COMMANDS
+ #define ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS 0
+#else
+ #define ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS configINCLUDE_TRACE_RELATED_CLI_COMMANDS
+#endif
+
+#ifndef ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM
+ #define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM ( 0 )
+#endif
+
+#ifndef ipconfigETHERNET_DRIVER_FILTERS_PACKETS
+ #define ipconfigETHERNET_DRIVER_FILTERS_PACKETS ( 0 )
+#endif
+
+#ifndef ipconfigWATCHDOG_TIMER
+ /* This macro will be called in every loop the IP-task makes. It may be
+ replaced by user-code that triggers a watchdog */
+ #define ipconfigWATCHDOG_TIMER()
+#endif
+
+#ifndef ipconfigUSE_CALLBACKS
+ #define ipconfigUSE_CALLBACKS ( 0 )
+#endif
+
+#if( ipconfigUSE_CALLBACKS != 0 )
+ #ifndef ipconfigIS_VALID_PROG_ADDRESS
+ /* Replace this macro with a test returning non-zero if the memory pointer to by x
+ * is valid memory which can contain executable code
+ * In fact this is an extra safety measure: if a handler points to invalid memory,
+ * it will not be called
+ */
+ #define ipconfigIS_VALID_PROG_ADDRESS(x) ( ( x ) != NULL )
+ #endif
+#endif
+
+#ifndef ipconfigHAS_INLINE_FUNCTIONS
+ #define ipconfigHAS_INLINE_FUNCTIONS ( 1 )
+#endif
+
+#ifndef portINLINE
+ #define portINLINE inline
+#endif
+
+#ifndef ipconfigZERO_COPY_TX_DRIVER
+ /* When non-zero, the buffers passed to the SEND routine may be passed
+ to DMA. As soon as sending is ready, the buffers must be released by
+ calling vReleaseNetworkBufferAndDescriptor(), */
+ #define ipconfigZERO_COPY_TX_DRIVER ( 0 )
+#endif
+
+#ifndef ipconfigZERO_COPY_RX_DRIVER
+ /* This define doesn't mean much to the driver, except that it makes
+ sure that pxPacketBuffer_to_NetworkBuffer() will be included. */
+ #define ipconfigZERO_COPY_RX_DRIVER ( 0 )
+#endif
+
+#ifndef ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM
+ #define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 0
+#endif
+
+#ifndef ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM
+ #define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 0
+#endif
+
+#ifndef ipconfigDHCP_REGISTER_HOSTNAME
+ #define ipconfigDHCP_REGISTER_HOSTNAME 0
+#endif
+
+#ifndef ipconfigSOCKET_HAS_USER_SEMAPHORE
+ #define ipconfigSOCKET_HAS_USER_SEMAPHORE 0
+#endif
+
+#ifndef ipconfigSUPPORT_SELECT_FUNCTION
+ #define ipconfigSUPPORT_SELECT_FUNCTION 0
+#endif
+
+#ifndef ipconfigTCP_KEEP_ALIVE
+ #define ipconfigTCP_KEEP_ALIVE 0
+#endif
+
+#ifndef ipconfigDNS_USE_CALLBACKS
+ #define ipconfigDNS_USE_CALLBACKS 0
+#endif
+
+#ifndef ipconfigSUPPORT_SIGNALS
+ #define ipconfigSUPPORT_SIGNALS 0
+#endif
+
+#ifndef ipconfigUSE_NBNS
+ #define ipconfigUSE_NBNS 0
+#endif
+
+#ifndef ipconfigTCP_HANG_PROTECTION
+ #define ipconfigTCP_HANG_PROTECTION 0
+#endif
+
+#ifndef ipconfigTCP_IP_SANITY
+ #define ipconfigTCP_IP_SANITY 0
+#endif
+
+#ifndef ipconfigARP_STORES_REMOTE_ADDRESSES
+ #define ipconfigARP_STORES_REMOTE_ADDRESSES 0
+#endif
+
+#ifndef ipconfigBUFFER_PADDING
+ /* Expert option: define a value for 'ipBUFFER_PADDING'.
+ When 'ipconfigBUFFER_PADDING' equals 0,
+ 'ipBUFFER_PADDING' will get a default value of 8 + 2 bytes. */
+ #define ipconfigBUFFER_PADDING 0
+#endif
+
+#ifndef ipconfigPACKET_FILLER_SIZE
+ #define ipconfigPACKET_FILLER_SIZE 2
+#endif
+
+#endif /* FREERTOS_DEFAULT_IP_CONFIG_H */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h
new file mode 100644
index 000000000..5caad67a6
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h
@@ -0,0 +1,173 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef FREERTOS_ARP_H
+#define FREERTOS_ARP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Application level configuration options. */
+#include "FreeRTOSIPConfig.h"
+#include "FreeRTOSIPConfigDefaults.h"
+#include "IPTraceMacroDefaults.h"
+
+/*-----------------------------------------------------------*/
+/* Miscellaneous structure and definitions. */
+/*-----------------------------------------------------------*/
+
+typedef struct xARP_CACHE_TABLE_ROW
+{
+ uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */
+ MACAddress_t xMACAddress; /* The MAC address of an ARP cache entry. */
+ uint8_t ucAge; /* A value that is periodically decremented but can also be refreshed by active communication. The ARP cache entry is removed if the value reaches zero. */
+ uint8_t ucValid; /* pdTRUE: xMACAddress is valid, pdFALSE: waiting for ARP reply */
+} ARPCacheRow_t;
+
+typedef enum
+{
+ eARPCacheMiss = 0, /* 0 An ARP table lookup did not find a valid entry. */
+ eARPCacheHit, /* 1 An ARP table lookup found a valid entry. */
+ eCantSendPacket /* 2 There is no IP address, or an ARP is still in progress, so the packet cannot be sent. */
+} eARPLookupResult_t;
+
+typedef enum
+{
+ eNotFragment = 0, /* The IP packet being sent is not part of a fragment. */
+ eFirstFragment, /* The IP packet being sent is the first in a set of fragmented packets. */
+ eFollowingFragment /* The IP packet being sent is part of a set of fragmented packets. */
+} eIPFragmentStatus_t;
+
+/*
+ * If ulIPAddress is already in the ARP cache table then reset the age of the
+ * entry back to its maximum value. If ulIPAddress is not already in the ARP
+ * cache table then add it - replacing the oldest current entry if there is not
+ * a free space available.
+ */
+void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress, const uint32_t ulIPAddress );
+
+#if( ipconfigARP_USE_CLASH_DETECTION != 0 )
+ /* Becomes non-zero if another device responded to a gratuitos ARP message. */
+ extern BaseType_t xARPHadIPClash;
+ /* MAC-address of the other device containing the same IP-address. */
+ extern MACAddress_t xARPClashMacAddress;
+#endif /* ipconfigARP_USE_CLASH_DETECTION */
+
+#if( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )
+
+ /*
+ * In some rare cases, it might be useful to remove a ARP cache entry of a
+ * known MAC address to make sure it gets refreshed.
+ */
+ uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress );
+
+#endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */
+
+/*
+ * Look for ulIPAddress in the ARP cache. If the IP address exists, copy the
+ * associated MAC address into pxMACAddress, refresh the ARP cache entry's
+ * age, and return eARPCacheHit. If the IP address does not exist in the ARP
+ * cache return eARPCacheMiss. If the packet cannot be sent for any reason
+ * (maybe DHCP is still in process, or the addressing needs a gateway but there
+ * isn't a gateway defined) then return eCantSendPacket.
+ */
+eARPLookupResult_t eARPGetCacheEntry( uint32_t *pulIPAddress, MACAddress_t * const pxMACAddress );
+
+#if( ipconfigUSE_ARP_REVERSED_LOOKUP != 0 )
+
+ /* Lookup an IP-address if only the MAC-address is known */
+ eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress, uint32_t *pulIPAddress );
+
+#endif
+/*
+ * Reduce the age count in each entry within the ARP cache. An entry is no
+ * longer considered valid and is deleted if its age reaches zero.
+ */
+void vARPAgeCache( void );
+
+/*
+ * Send out an ARP request for the IP address contained in pxNetworkBuffer, and
+ * add an entry into the ARP table that indicates that an ARP reply is
+ * outstanding so re-transmissions can be generated.
+ */
+void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
+
+/*
+ * After DHCP is ready and when changing IP address, force a quick send of our new IP
+ * address
+ */
+void vARPSendGratuitous( void );
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* FREERTOS_ARP_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h
new file mode 100644
index 000000000..b432e3c53
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h
@@ -0,0 +1,119 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef FREERTOS_DHCP_H
+#define FREERTOS_DHCP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Application level configuration options. */
+#include "FreeRTOSIPConfig.h"
+#include "IPTraceMacroDefaults.h"
+
+/* Used in the DHCP callback if ipconfigUSE_DHCP_HOOK is set to 1. */
+typedef enum eDHCP_PHASE
+{
+ eDHCPPhasePreDiscover, /* Driver is about to send a DHCP discovery. */
+ eDHCPPhasePreRequest, /* Driver is about to request DHCP an IP address. */
+#if( ipconfigDHCP_SEND_DISCOVER_AFTER_AUTO_IP != 0 )
+ eDHCPPhasePreLLA, /* Driver is about to try get an LLA address */
+#endif /* ipconfigDHCP_SEND_DISCOVER_AFTER_AUTO_IP */
+} eDHCPCallbackPhase_t;
+
+/* Used in the DHCP callback if ipconfigUSE_DHCP_HOOK is set to 1. */
+typedef enum eDHCP_ANSWERS
+{
+ eDHCPContinue, /* Continue the DHCP process */
+ eDHCPUseDefaults, /* Stop DHCP and use the static defaults. */
+ eDHCPStopNoChanges, /* Stop DHCP and continue with current settings. */
+} eDHCPCallbackAnswer_t;
+
+/*
+ * NOT A PUBLIC API FUNCTION.
+ */
+void vDHCPProcess( BaseType_t xReset );
+
+/* Internal call: returns true if socket is the current DHCP socket */
+BaseType_t xIsDHCPSocket( Socket_t xSocket );
+
+/* Prototype of the hook (or callback) function that must be provided by the
+application if ipconfigUSE_DHCP_HOOK is set to 1. See the following URL for
+usage information:
+http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html#ipconfigUSE_DHCP_HOOK
+*/
+eDHCPCallbackAnswer_t xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase, uint32_t ulIPAddress );
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* FREERTOS_DHCP_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h
new file mode 100644
index 000000000..45144912c
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h
@@ -0,0 +1,165 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef FREERTOS_DNS_H
+#define FREERTOS_DNS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Application level configuration options. */
+#include "FreeRTOSIPConfig.h"
+#include "IPTraceMacroDefaults.h"
+
+
+/* The Link-local Multicast Name Resolution (LLMNR)
+ * is included.
+ * Note that a special MAC address is required in addition to the NIC's actual
+ * MAC address: 01:00:5E:00:00:FC
+ *
+ * The target IP address will be 224.0.0.252
+ */
+#if( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
+ #define ipLLMNR_IP_ADDR 0xE00000FC
+#else
+ #define ipLLMNR_IP_ADDR 0xFC0000E0
+#endif /* ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN */
+
+#define ipLLMNR_PORT 5355 /* Standard LLMNR port. */
+#define ipDNS_PORT 53 /* Standard DNS port. */
+#define ipDHCP_CLIENT 67
+#define ipDHCP_SERVER 68
+#define ipNBNS_PORT 137 /* NetBIOS Name Service. */
+#define ipNBDGM_PORT 138 /* Datagram Service, not included. */
+
+/*
+ * The following function should be provided by the user and return true if it
+ * matches the domain name.
+ */
+extern BaseType_t xApplicationDNSQueryHook( const char *pcName );
+
+/*
+ * LLMNR is very similar to DNS, so is handled by the DNS routines.
+ */
+uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+#if( ipconfigUSE_LLMNR == 1 )
+ extern const MACAddress_t xLLMNR_MacAdress;
+#endif /* ipconfigUSE_LLMNR */
+
+#if( ipconfigUSE_NBNS != 0 )
+
+ /*
+ * Inspect a NetBIOS Names-Service message. If the name matches with ours
+ * (xApplicationDNSQueryHook returns true) an answer will be sent back.
+ * Note that LLMNR is a better protocol for name services on a LAN as it is
+ * less polluted
+ */
+ uint32_t ulNBNSHandlePacket (NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+#endif /* ipconfigUSE_NBNS */
+
+#if( ipconfigUSE_DNS_CACHE != 0 )
+
+ uint32_t FreeRTOS_dnslookup( const char *pcHostName );
+
+#endif /* ipconfigUSE_DNS_CACHE != 0 */
+
+#if( ipconfigDNS_USE_CALLBACKS != 0 )
+
+ /*
+ * Users may define this type of function as a callback.
+ * It will be called when a DNS reply is received or when a timeout has been reached.
+ */
+ typedef void (* FOnDNSEvent ) ( const char * /* pcName */, void * /* pvSearchID */, uint32_t /* ulIPAddress */ );
+
+ /*
+ * Asynchronous version of gethostbyname()
+ * xTimeout is in units of ms.
+ */
+ uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName, FOnDNSEvent pCallback, void *pvSearchID, TickType_t xTimeout );
+ void FreeRTOS_gethostbyname_cancel( void *pvSearchID );
+
+#endif
+
+/*
+ * FULL, UP-TO-DATE AND MAINTAINED REFERENCE DOCUMENTATION FOR ALL THESE
+ * FUNCTIONS IS AVAILABLE ON THE FOLLOWING URL:
+ * _TBD_ Add URL
+ */
+uint32_t FreeRTOS_gethostbyname( const char *pcHostName );
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* FREERTOS_DNS_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h
new file mode 100644
index 000000000..59311c419
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h
@@ -0,0 +1,350 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef FREERTOS_IP_H
+#define FREERTOS_IP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Application level configuration options. */
+#include "FreeRTOSIPConfig.h"
+#include "FreeRTOSIPConfigDefaults.h"
+#include "IPTraceMacroDefaults.h"
+
+/* Some constants defining the sizes of several parts of a packet */
+#define ipSIZE_OF_ETH_HEADER 14u
+#define ipSIZE_OF_IPv4_HEADER 20u
+#define ipSIZE_OF_IGMP_HEADER 8u
+#define ipSIZE_OF_ICMP_HEADER 8u
+#define ipSIZE_OF_UDP_HEADER 8u
+#define ipSIZE_OF_TCP_HEADER 20u
+
+
+/* The number of octets in the MAC and IP addresses respectively. */
+#define ipMAC_ADDRESS_LENGTH_BYTES ( 6 )
+#define ipIP_ADDRESS_LENGTH_BYTES ( 4 )
+
+/* IP protocol definitions. */
+#define ipPROTOCOL_ICMP ( 1 )
+#define ipPROTOCOL_IGMP ( 2 )
+#define ipPROTOCOL_TCP ( 6 )
+#define ipPROTOCOL_UDP ( 17 )
+
+/* Dimensions the buffers that are filled by received Ethernet frames. */
+#define ipSIZE_OF_ETH_CRC_BYTES ( 4UL )
+#define ipSIZE_OF_ETH_OPTIONAL_802_1Q_TAG_BYTES ( 4UL )
+#define ipTOTAL_ETHERNET_FRAME_SIZE ( ( ( uint32_t ) ipconfigNETWORK_MTU ) + ( ( uint32_t ) ipSIZE_OF_ETH_HEADER ) + ipSIZE_OF_ETH_CRC_BYTES + ipSIZE_OF_ETH_OPTIONAL_802_1Q_TAG_BYTES )
+
+/*_RB_ Comment may need updating. */
+/* Space left at the beginning of a network buffer storage area to store a
+pointer back to the network buffer. Should be a multiple of 8 to ensure 8 byte
+alignment is maintained on architectures that require it.
+
+In order to get a 32-bit alignment of network packets, an offset of 2 bytes
+would be desirable, as defined by ipconfigPACKET_FILLER_SIZE. So the malloc'd
+buffer will have the following contents:
+ uint32_t pointer; // word-aligned
+ uchar_8 filler[6];
+ << ETH-header >> // half-word-aligned
+ uchar_8 dest[6]; // start of pucEthernetBuffer
+ uchar_8 dest[6];
+ uchar16_t type;
+ << IP-header >> // word-aligned
+ uint8_t ucVersionHeaderLength;
+ etc
+ */
+#if( ipconfigBUFFER_PADDING != 0 )
+ #define ipBUFFER_PADDING ipconfigBUFFER_PADDING
+#else
+ #define ipBUFFER_PADDING ( 8u + ipconfigPACKET_FILLER_SIZE )
+#endif
+
+/* The structure used to store buffers and pass them around the network stack.
+Buffers can be in use by the stack, in use by the network interface hardware
+driver, or free (not in use). */
+typedef struct xNETWORK_BUFFER
+{
+ ListItem_t xBufferListItem; /* Used to reference the buffer form the free buffer list or a socket. */
+ uint32_t ulIPAddress; /* Source or destination IP address, depending on usage scenario. */
+ uint8_t *pucEthernetBuffer; /* Pointer to the start of the Ethernet frame. */
+ size_t xDataLength; /* Starts by holding the total Ethernet frame length, then the UDP/TCP payload length. */
+ uint16_t usPort; /* Source or destination port, depending on usage scenario. */
+ uint16_t usBoundPort; /* The port to which a transmitting socket is bound. */
+ #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
+ struct xNETWORK_BUFFER *pxNextBuffer; /* Possible optimisation for expert users - requires network driver support. */
+ #endif
+} NetworkBufferDescriptor_t;
+
+#include "pack_struct_start.h"
+struct xMAC_ADDRESS
+{
+ uint8_t ucBytes[ ipMAC_ADDRESS_LENGTH_BYTES ];
+}
+#include "pack_struct_end.h"
+
+typedef struct xMAC_ADDRESS MACAddress_t;
+
+typedef enum eNETWORK_EVENTS
+{
+ eNetworkUp, /* The network is configured. */
+ eNetworkDown /* The network connection has been lost. */
+} eIPCallbackEvent_t;
+
+typedef enum ePING_REPLY_STATUS
+{
+ eSuccess = 0, /* A correct reply has been received for an outgoing ping. */
+ eInvalidChecksum, /* A reply was received for an outgoing ping but the checksum of the reply was incorrect. */
+ eInvalidData /* A reply was received to an outgoing ping but the payload of the reply was not correct. */
+} ePingReplyStatus_t;
+
+/* Endian related definitions. */
+#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
+
+ /* FreeRTOS_htons / FreeRTOS_htonl: some platforms might have built-in versions
+ using a single instruction so allow these versions to be overridden. */
+ #ifndef FreeRTOS_htons
+ #define FreeRTOS_htons( usIn ) ( (uint16_t) ( ( ( usIn ) << 8U ) | ( ( usIn ) >> 8U ) ) )
+ #endif
+
+ #ifndef FreeRTOS_htonl
+ #define FreeRTOS_htonl( ulIn ) \
+ ( \
+ ( uint32_t ) \
+ ( \
+ ( ( ( ( uint32_t ) ( ulIn ) ) ) << 24 ) | \
+ ( ( ( ( uint32_t ) ( ulIn ) ) & 0x0000ff00UL ) << 8 ) | \
+ ( ( ( ( uint32_t ) ( ulIn ) ) & 0x00ff0000UL ) >> 8 ) | \
+ ( ( ( ( uint32_t ) ( ulIn ) ) ) >> 24 ) \
+ ) \
+ )
+ #endif
+
+#else /* ipconfigBYTE_ORDER */
+
+ #define FreeRTOS_htons( x ) ( ( uint16_t ) ( x ) )
+ #define FreeRTOS_htonl( x ) ( ( uint32_t ) ( x ) )
+
+#endif /* ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN */
+
+#define FreeRTOS_ntohs( x ) FreeRTOS_htons( x )
+#define FreeRTOS_ntohl( x ) FreeRTOS_htonl( x )
+
+#if( ipconfigHAS_INLINE_FUNCTIONS == 1 )
+
+ static portINLINE int32_t FreeRTOS_max_int32 (int32_t a, int32_t b);
+ static portINLINE uint32_t FreeRTOS_max_uint32 (uint32_t a, uint32_t b);
+ static portINLINE int32_t FreeRTOS_min_int32 (int32_t a, int32_t b);
+ static portINLINE uint32_t FreeRTOS_min_uint32 (uint32_t a, uint32_t b);
+ static portINLINE uint32_t FreeRTOS_round_up (uint32_t a, uint32_t d);
+ static portINLINE uint32_t FreeRTOS_round_down (uint32_t a, uint32_t d);
+ static portINLINE BaseType_t FreeRTOS_min_BaseType (BaseType_t a, BaseType_t b);
+ static portINLINE BaseType_t FreeRTOS_max_BaseType (BaseType_t a, BaseType_t b);
+ static portINLINE UBaseType_t FreeRTOS_max_UBaseType (UBaseType_t a, UBaseType_t b);
+ static portINLINE UBaseType_t FreeRTOS_min_UBaseType (UBaseType_t a, UBaseType_t b);
+
+
+ static portINLINE int32_t FreeRTOS_max_int32 (int32_t a, int32_t b) { return a >= b ? a : b; }
+ static portINLINE uint32_t FreeRTOS_max_uint32 (uint32_t a, uint32_t b) { return a >= b ? a : b; }
+ static portINLINE int32_t FreeRTOS_min_int32 (int32_t a, int32_t b) { return a <= b ? a : b; }
+ static portINLINE uint32_t FreeRTOS_min_uint32 (uint32_t a, uint32_t b) { return a <= b ? a : b; }
+ static portINLINE uint32_t FreeRTOS_round_up (uint32_t a, uint32_t d) { return d * ( ( a + d - 1u ) / d ); }
+ static portINLINE uint32_t FreeRTOS_round_down (uint32_t a, uint32_t d) { return d * ( a / d ); }
+
+ static portINLINE BaseType_t FreeRTOS_max_BaseType (BaseType_t a, BaseType_t b) { return a >= b ? a : b; }
+ static portINLINE UBaseType_t FreeRTOS_max_UBaseType (UBaseType_t a, UBaseType_t b) { return a >= b ? a : b; }
+ static portINLINE BaseType_t FreeRTOS_min_BaseType (BaseType_t a, BaseType_t b) { return a <= b ? a : b; }
+ static portINLINE UBaseType_t FreeRTOS_min_UBaseType (UBaseType_t a, UBaseType_t b) { return a <= b ? a : b; }
+
+#else
+
+ #define FreeRTOS_max_int32(a,b) ( ( ( int32_t ) ( a ) ) >= ( ( int32_t ) ( b ) ) ? ( ( int32_t ) ( a ) ) : ( ( int32_t ) ( b ) ) )
+ #define FreeRTOS_max_uint32(a,b) ( ( ( uint32_t ) ( a ) ) >= ( ( uint32_t ) ( b ) ) ? ( ( uint32_t ) ( a ) ) : ( ( uint32_t ) ( b ) ) )
+
+ #define FreeRTOS_min_int32(a,b) ( ( ( int32_t ) a ) <= ( ( int32_t ) b ) ? ( ( int32_t ) a ) : ( ( int32_t ) b ) )
+ #define FreeRTOS_min_uint32(a,b) ( ( ( uint32_t ) a ) <= ( ( uint32_t ) b ) ? ( ( uint32_t ) a ) : ( ( uint32_t ) b ) )
+
+ /* Round-up: a = d * ( ( a + d - 1 ) / d ) */
+ #define FreeRTOS_round_up(a,d) ( ( ( uint32_t ) ( d ) ) * ( ( ( ( uint32_t ) ( a ) ) + ( ( uint32_t ) ( d ) ) - 1UL ) / ( ( uint32_t ) ( d ) ) ) )
+ #define FreeRTOS_round_down(a,d) ( ( ( uint32_t ) ( d ) ) * ( ( ( uint32_t ) ( a ) ) / ( ( uint32_t ) ( d ) ) ) )
+
+ #define FreeRTOS_max_BaseType(a, b) ( ( ( BaseType_t ) ( a ) ) >= ( ( BaseType_t ) ( b ) ) ? ( ( BaseType_t ) ( a ) ) : ( ( BaseType_t ) ( b ) ) )
+ #define FreeRTOS_max_UBaseType(a, b) ( ( ( UBaseType_t ) ( a ) ) >= ( ( UBaseType_t ) ( b ) ) ? ( ( UBaseType_t ) ( a ) ) : ( ( UBaseType_t ) ( b ) ) )
+ #define FreeRTOS_min_BaseType(a, b) ( ( ( BaseType_t ) ( a ) ) <= ( ( BaseType_t ) ( b ) ) ? ( ( BaseType_t ) ( a ) ) : ( ( BaseType_t ) ( b ) ) )
+ #define FreeRTOS_min_UBaseType(a, b) ( ( ( UBaseType_t ) ( a ) ) <= ( ( UBaseType_t ) ( b ) ) ? ( ( UBaseType_t ) ( a ) ) : ( ( UBaseType_t ) ( b ) ) )
+
+#endif /* ipconfigHAS_INLINE_FUNCTIONS */
+
+#define pdMS_TO_MIN_TICKS( xTimeInMs ) ( pdMS_TO_TICKS( ( xTimeInMs ) ) < ( ( TickType_t ) 1 ) ? ( ( TickType_t ) 1 ) : pdMS_TO_TICKS( ( xTimeInMs ) ) )
+
+#ifndef pdTRUE_SIGNED
+ /* Temporary solution: eventually the defines below will appear in 'Source\include\projdefs.h' */
+ #define pdTRUE_SIGNED pdTRUE
+ #define pdFALSE_SIGNED pdFALSE
+ #define pdTRUE_UNSIGNED ( ( UBaseType_t ) 1u )
+ #define pdFALSE_UNSIGNED ( ( UBaseType_t ) 0u )
+#endif
+
+/*
+ * FULL, UP-TO-DATE AND MAINTAINED REFERENCE DOCUMENTATION FOR ALL THESE
+ * FUNCTIONS IS AVAILABLE ON THE FOLLOWING URL:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FreeRTOS_TCP_API_Functions.html
+ */
+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 ] );
+
+void * FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks );
+void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress );
+void FreeRTOS_SetAddressConfiguration( const uint32_t *pulIPAddress, const uint32_t *pulNetMask, const uint32_t *pulGatewayAddress, const uint32_t *pulDNSServerAddress );
+BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, TickType_t xBlockTimeTicks );
+void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer );
+const uint8_t * FreeRTOS_GetMACAddress( void );
+void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent );
+void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, uint16_t usIdentifier );
+uint32_t FreeRTOS_GetIPAddress( void );
+void FreeRTOS_SetIPAddress( uint32_t ulIPAddress );
+void FreeRTOS_SetNetmask( uint32_t ulNetmask );
+void FreeRTOS_SetGatewayAddress( uint32_t ulGatewayAddress );
+uint32_t FreeRTOS_GetGatewayAddress( void );
+uint32_t FreeRTOS_GetDNSServerAddress( void );
+uint32_t FreeRTOS_GetNetmask( void );
+void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress );
+BaseType_t FreeRTOS_IsNetworkUp( void );
+
+#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+ UBaseType_t uxGetMinimumIPQueueSpace( void );
+#endif
+
+/*
+ * Defined in FreeRTOS_Sockets.c
+ * //_RB_ Don't think this comment is correct. If this is for internal use only it should appear after all the public API functions and not start with FreeRTOS_.
+ * Socket has had activity, reset the timer so it will not be closed
+ * because of inactivity
+ */
+const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState);
+
+/* _HT_ Temporary: show all valid ARP entries
+ */
+void FreeRTOS_PrintARPCache( void );
+void FreeRTOS_ClearARP( void );
+
+#if( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
+
+ /* DHCP has an option for clients to register their hostname. It doesn't
+ have much use, except that a device can be found in a router along with its
+ name. If this option is used the callback below must be provided by the
+ application writer to return a const string, denoting the device's name. */
+ const char *pcApplicationHostnameHook( void );
+
+#endif /* ipconfigDHCP_REGISTER_HOSTNAME */
+
+
+/* For backward compatibility define old structure names to the newer equivalent
+structure name. */
+#ifndef ipconfigENABLE_BACKWARD_COMPATIBILITY
+ #define ipconfigENABLE_BACKWARD_COMPATIBILITY 1
+#endif
+
+#if( ipconfigENABLE_BACKWARD_COMPATIBILITY == 1 )
+ #define xIPStackEvent_t IPStackEvent_t
+ #define xNetworkBufferDescriptor_t NetworkBufferDescriptor_t
+ #define xMACAddress_t MACAddress_t
+ #define xWinProperties_t WinProperties_t
+ #define xSocket_t Socket_t
+ #define xSocketSet_t SocketSet_t
+ #define ipSIZE_OF_IP_HEADER ipSIZE_OF_IPv4_HEADER
+
+ /* Since August 2016, the public types and fields below have changed name:
+ abbreviations TCP/UDP are now written in capitals, and type names now end with "_t". */
+ #define FOnConnected FOnConnected_t
+ #define FOnTcpReceive FOnTCPReceive_t
+ #define FOnTcpSent FOnTCPSent_t
+ #define FOnUdpReceive FOnUDPReceive_t
+ #define FOnUdpSent FOnUDPSent_t
+
+ #define pOnTcpConnected pxOnTCPConnected
+ #define pOnTcpReceive pxOnTCPReceive
+ #define pOnTcpSent pxOnTCPSent
+ #define pOnUdpReceive pxOnUDPReceive
+ #define pOnUdpSent pxOnUDPSent
+
+ #define FOnUdpSent FOnUDPSent_t
+ #define FOnTcpSent FOnTCPSent_t
+#endif /* ipconfigENABLE_BACKWARD_COMPATIBILITY */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* FREERTOS_IP_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h
new file mode 100644
index 000000000..6af875add
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h
@@ -0,0 +1,840 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef FREERTOS_IP_PRIVATE_H
+#define FREERTOS_IP_PRIVATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Application level configuration options. */
+#include "FreeRTOSIPConfig.h"
+#include "FreeRTOSIPConfigDefaults.h"
+#include "FreeRTOS_Sockets.h"
+#include "IPTraceMacroDefaults.h"
+#include "FreeRTOS_Stream_Buffer.h"
+#if( ipconfigUSE_TCP == 1 )
+ #include "FreeRTOS_TCP_WIN.h"
+ #include "FreeRTOS_TCP_IP.h"
+#endif
+
+#include "event_groups.h"
+
+typedef struct xNetworkAddressingParameters
+{
+ uint32_t ulDefaultIPAddress;
+ uint32_t ulNetMask;
+ uint32_t ulGatewayAddress;
+ uint32_t ulDNSServerAddress;
+ uint32_t ulBroadcastAddress;
+} NetworkAddressingParameters_t;
+
+extern BaseType_t xTCPWindowLoggingLevel;
+
+/*-----------------------------------------------------------*/
+/* Protocol headers. */
+/*-----------------------------------------------------------*/
+
+#include "pack_struct_start.h"
+struct xETH_HEADER
+{
+ MACAddress_t xDestinationAddress; /* 0 + 6 = 6 */
+ MACAddress_t xSourceAddress; /* 6 + 6 = 12 */
+ uint16_t usFrameType; /* 12 + 2 = 14 */
+}
+#include "pack_struct_end.h"
+typedef struct xETH_HEADER EthernetHeader_t;
+
+#include "pack_struct_start.h"
+struct xARP_HEADER
+{
+ uint16_t usHardwareType; /* 0 + 2 = 2 */
+ uint16_t usProtocolType; /* 2 + 2 = 4 */
+ uint8_t ucHardwareAddressLength; /* 4 + 1 = 5 */
+ uint8_t ucProtocolAddressLength; /* 5 + 1 = 6 */
+ uint16_t usOperation; /* 6 + 2 = 8 */
+ MACAddress_t xSenderHardwareAddress; /* 8 + 6 = 14 */
+ uint8_t ucSenderProtocolAddress[ 4 ]; /* 14 + 4 = 18 */
+ MACAddress_t xTargetHardwareAddress; /* 18 + 6 = 24 */
+ uint32_t ulTargetProtocolAddress; /* 24 + 4 = 28 */
+}
+#include "pack_struct_end.h"
+typedef struct xARP_HEADER ARPHeader_t;
+
+#include "pack_struct_start.h"
+struct xIP_HEADER
+{
+ uint8_t ucVersionHeaderLength; /* 0 + 1 = 1 */
+ uint8_t ucDifferentiatedServicesCode; /* 1 + 1 = 2 */
+ uint16_t usLength; /* 2 + 2 = 4 */
+ uint16_t usIdentification; /* 4 + 2 = 6 */
+ uint16_t usFragmentOffset; /* 6 + 2 = 8 */
+ uint8_t ucTimeToLive; /* 8 + 1 = 9 */
+ uint8_t ucProtocol; /* 9 + 1 = 10 */
+ uint16_t usHeaderChecksum; /* 10 + 2 = 12 */
+ uint32_t ulSourceIPAddress; /* 12 + 4 = 16 */
+ uint32_t ulDestinationIPAddress; /* 16 + 4 = 20 */
+}
+#include "pack_struct_end.h"
+typedef struct xIP_HEADER IPHeader_t;
+
+#include "pack_struct_start.h"
+struct xIGMP_HEADER
+{
+ uint8_t ucVersionType; /* 0 + 1 = 1 */
+ uint8_t ucMaxResponseTime; /* 1 + 1 = 2 */
+ uint16_t usChecksum; /* 2 + 2 = 4 */
+ uint32_t usGroupAddress; /* 4 + 4 = 8 */
+}
+#include "pack_struct_end.h"
+typedef struct xIGMP_HEADER IGMPHeader_t;
+
+#include "pack_struct_start.h"
+struct xICMP_HEADER
+{
+ uint8_t ucTypeOfMessage; /* 0 + 1 = 1 */
+ uint8_t ucTypeOfService; /* 1 + 1 = 2 */
+ uint16_t usChecksum; /* 2 + 2 = 4 */
+ uint16_t usIdentifier; /* 4 + 2 = 6 */
+ uint16_t usSequenceNumber; /* 6 + 2 = 8 */
+}
+#include "pack_struct_end.h"
+typedef struct xICMP_HEADER ICMPHeader_t;
+
+#include "pack_struct_start.h"
+struct xUDP_HEADER
+{
+ uint16_t usSourcePort; /* 0 + 2 = 2 */
+ uint16_t usDestinationPort; /* 2 + 2 = 4 */
+ uint16_t usLength; /* 4 + 2 = 6 */
+ uint16_t usChecksum; /* 6 + 2 = 8 */
+}
+#include "pack_struct_end.h"
+typedef struct xUDP_HEADER UDPHeader_t;
+
+#include "pack_struct_start.h"
+struct xTCP_HEADER
+{
+ uint16_t usSourcePort; /* + 2 = 2 */
+ uint16_t usDestinationPort; /* + 2 = 4 */
+ uint32_t ulSequenceNumber; /* + 4 = 8 */
+ uint32_t ulAckNr; /* + 4 = 12 */
+ uint8_t ucTCPOffset; /* + 1 = 13 */
+ uint8_t ucTCPFlags; /* + 1 = 14 */
+ uint16_t usWindow; /* + 2 = 15 */
+ uint16_t usChecksum; /* + 2 = 18 */
+ uint16_t usUrgent; /* + 2 = 20 */
+#if ipconfigUSE_TCP == 1
+ /* the option data is not a part of the TCP header */
+ uint8_t ucOptdata[ipSIZE_TCP_OPTIONS]; /* + 12 = 32 */
+#endif
+}
+#include "pack_struct_end.h"
+typedef struct xTCP_HEADER TCPHeader_t;
+
+#include "pack_struct_start.h"
+struct xPSEUDO_HEADER
+{
+ uint32_t ulSourceAddress;
+ uint32_t ulDestinationAddress;
+ uint8_t ucZeros;
+ uint8_t ucProtocol;
+ uint16_t usUDPLength;
+}
+#include "pack_struct_end.h"
+typedef struct xPSEUDO_HEADER PseudoHeader_t;
+
+/*-----------------------------------------------------------*/
+/* Nested protocol packets. */
+/*-----------------------------------------------------------*/
+
+#include "pack_struct_start.h"
+struct xARP_PACKET
+{
+ EthernetHeader_t xEthernetHeader; /* 0 + 14 = 14 */
+ ARPHeader_t xARPHeader; /* 14 + 28 = 42 */
+}
+#include "pack_struct_end.h"
+typedef struct xARP_PACKET ARPPacket_t;
+
+#include "pack_struct_start.h"
+struct xIP_PACKET
+{
+ EthernetHeader_t xEthernetHeader;
+ IPHeader_t xIPHeader;
+}
+#include "pack_struct_end.h"
+typedef struct xIP_PACKET IPPacket_t;
+
+#include "pack_struct_start.h"
+struct xICMP_PACKET
+{
+ EthernetHeader_t xEthernetHeader;
+ IPHeader_t xIPHeader;
+ ICMPHeader_t xICMPHeader;
+}
+#include "pack_struct_end.h"
+typedef struct xICMP_PACKET ICMPPacket_t;
+
+#include "pack_struct_start.h"
+struct xUDP_PACKET
+{
+ EthernetHeader_t xEthernetHeader; /* 0 + 14 = 14 */
+ IPHeader_t xIPHeader; /* 14 + 20 = 34 */
+ UDPHeader_t xUDPHeader; /* 34 + 8 = 42 */
+}
+#include "pack_struct_end.h"
+typedef struct xUDP_PACKET UDPPacket_t;
+
+#include "pack_struct_start.h"
+struct xTCP_PACKET
+{
+ EthernetHeader_t xEthernetHeader; /* 0 + 14 = 14 */
+ IPHeader_t xIPHeader; /* 14 + 20 = 34 */
+ TCPHeader_t xTCPHeader; /* 34 + 32 = 66 */
+}
+#include "pack_struct_end.h"
+typedef struct xTCP_PACKET TCPPacket_t;
+
+typedef union XPROT_PACKET
+{
+ ARPPacket_t xARPPacket;
+ TCPPacket_t xTCPPacket;
+ UDPPacket_t xUDPPacket;
+ ICMPPacket_t xICMPPacket;
+} ProtocolPacket_t;
+
+
+/* The maximum UDP payload length. */
+#define ipMAX_UDP_PAYLOAD_LENGTH ( ( ipconfigNETWORK_MTU - ipSIZE_OF_IPv4_HEADER ) - ipSIZE_OF_UDP_HEADER )
+
+typedef enum
+{
+ eReleaseBuffer = 0, /* Processing the frame did not find anything to do - just release the buffer. */
+ eProcessBuffer, /* An Ethernet frame has a valid address - continue process its contents. */
+ eReturnEthernetFrame, /* The Ethernet frame contains an ARP or ICMP packet that can be returned to its source. */
+ eFrameConsumed /* Processing the Ethernet packet contents resulted in the payload being sent to the stack. */
+} eFrameProcessingResult_t;
+
+typedef enum
+{
+ eNoEvent = -1,
+ eNetworkDownEvent, /* 0: The network interface has been lost and/or needs [re]connecting. */
+ eNetworkRxEvent, /* 1: The network interface has queued a received Ethernet frame. */
+ eARPTimerEvent, /* 2: The ARP timer expired. */
+ eStackTxEvent, /* 3: The software stack has queued a packet to transmit. */
+ eDHCPEvent, /* 4: Process the DHCP state machine. */
+ eTCPTimerEvent, /* 5: See if any TCP socket needs attention. */
+ eTCPAcceptEvent, /* 6: Client API FreeRTOS_accept() waiting for client connections. */
+ eTCPNetStat, /* 7: IP-task is asked to produce a netstat listing. */
+ eSocketBindEvent, /* 8: Send a message to the IP-task to bind a socket to a port. */
+ eSocketCloseEvent, /* 9: Send a message to the IP-task to close a socket. */
+ eSocketSelectEvent, /*10: Send a message to the IP-task for select(). */
+ eSocketSignalEvent, /*11: A socket must be signalled. */
+} eIPEvent_t;
+
+typedef struct IP_TASK_COMMANDS
+{
+ eIPEvent_t eEventType;
+ void *pvData;
+} IPStackEvent_t;
+
+#define ipBROADCAST_IP_ADDRESS 0xffffffffUL
+
+/* Offset into the Ethernet frame that is used to temporarily store information
+on the fragmentation status of the packet being sent. The value is important,
+as it is past the location into which the destination address will get placed. */
+#define ipFRAGMENTATION_PARAMETERS_OFFSET ( 6 )
+#define ipSOCKET_OPTIONS_OFFSET ( 6 )
+
+/* Only used when outgoing fragmentation is being used (FreeRTOSIPConfig.h
+setting. */
+#define ipGET_UDP_PAYLOAD_OFFSET_FOR_FRAGMENT( usFragmentOffset ) ( ( ( usFragmentOffset ) == 0 ) ? ipUDP_PAYLOAD_OFFSET_IPv4 : ipIP_PAYLOAD_OFFSET )
+
+/* The offset into a UDP packet at which the UDP data (payload) starts. */
+#define ipUDP_PAYLOAD_OFFSET_IPv4 ( sizeof( UDPPacket_t ) )
+
+/* The offset into an IP packet into which the IP data (payload) starts. */
+#define ipIP_PAYLOAD_OFFSET ( sizeof( IPPacket_t ) )
+
+#include "pack_struct_start.h"
+struct xUDP_IP_FRAGMENT_PARAMETERS
+{
+ uint8_t ucSocketOptions;
+ uint8_t ucPadFor16BitAlignment;
+ uint16_t usFragmentedPacketOffset;
+ uint16_t usFragmentLength;
+ uint16_t usPayloadChecksum;
+}
+#include "pack_struct_end.h"
+typedef struct xUDP_IP_FRAGMENT_PARAMETERS IPFragmentParameters_t;
+
+#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
+
+ /* Ethernet frame types. */
+ #define ipARP_FRAME_TYPE ( 0x0608U )
+ #define ipIPv4_FRAME_TYPE ( 0x0008U )
+
+ /* ARP related definitions. */
+ #define ipARP_PROTOCOL_TYPE ( 0x0008U )
+ #define ipARP_HARDWARE_TYPE_ETHERNET ( 0x0100U )
+ #define ipARP_REQUEST ( 0x0100U )
+ #define ipARP_REPLY ( 0x0200U )
+
+#else
+
+ /* Ethernet frame types. */
+ #define ipARP_FRAME_TYPE ( 0x0806U )
+ #define ipIPv4_FRAME_TYPE ( 0x0800U )
+
+ /* ARP related definitions. */
+ #define ipARP_PROTOCOL_TYPE ( 0x0800U )
+ #define ipARP_HARDWARE_TYPE_ETHERNET ( 0x0001U )
+ #define ipARP_REQUEST ( 0x0001 )
+ #define ipARP_REPLY ( 0x0002 )
+
+#endif /* ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN */
+
+
+/* For convenience, a MAC address of all zeros and another of all 0xffs are
+defined const for quick reference. */
+extern const MACAddress_t xBroadcastMACAddress; /* all 0xff's */
+extern uint16_t usPacketIdentifier;
+
+/* Define a default UDP packet header (declared in FreeRTOS_UDP_IP.c) */
+typedef union xUDPPacketHeader
+{
+ uint8_t ucBytes[24];
+ uint32_t ulWords[6];
+} UDPPacketHeader_t;
+extern UDPPacketHeader_t xDefaultPartUDPPacketHeader;
+
+/* Structure that stores the netmask, gateway address and DNS server addresses. */
+extern NetworkAddressingParameters_t xNetworkAddressing;
+
+/* Structure that stores the defaults for netmask, gateway address and DNS.
+These values will be copied to 'xNetworkAddressing' in case DHCP is not used,
+and also in case DHCP does not lead to a confirmed request. */
+extern NetworkAddressingParameters_t xDefaultAddressing;
+
+/* True when BufferAllocation_1.c was included, false for BufferAllocation_2.c */
+extern const BaseType_t xBufferAllocFixedSize;
+
+/* Defined in FreeRTOS_Sockets.c */
+#if ( ipconfigUSE_TCP == 1 )
+ extern List_t xBoundTCPSocketsList;
+#endif
+
+/* The local IP address is accessed from within xDefaultPartUDPPacketHeader,
+rather than duplicated in its own variable. */
+#define ipLOCAL_IP_ADDRESS_POINTER ( ( uint32_t * ) &( xDefaultPartUDPPacketHeader.ulWords[ 20u / sizeof(uint32_t) ] ) )
+
+/* The local MAC address is accessed from within xDefaultPartUDPPacketHeader,
+rather than duplicated in its own variable. */
+#define ipLOCAL_MAC_ADDRESS ( &xDefaultPartUDPPacketHeader.ucBytes[0] )
+
+/* ICMP packets are sent using the same function as UDP packets. The port
+number is used to distinguish between the two, as 0 is an invalid UDP port. */
+#define ipPACKET_CONTAINS_ICMP_DATA ( 0 )
+
+/* For now, the lower 8 bits in 'xEventBits' will be reserved for the above
+socket events. */
+#define SOCKET_EVENT_BIT_COUNT 8
+
+#define vSetField16( pxBase, xType, xField, usValue ) \
+{ \
+ ( ( uint8_t* )( pxBase ) ) [ offsetof( xType, xField ) + 0 ] = ( uint8_t ) ( ( usValue ) >> 8 ); \
+ ( ( uint8_t* )( pxBase ) ) [ offsetof( xType, xField ) + 1 ] = ( uint8_t ) ( ( usValue ) & 0xff ); \
+}
+
+#define vSetField32( pxBase, xType, xField, ulValue ) \
+{ \
+ ( (uint8_t*)( pxBase ) ) [ offsetof( xType, xField ) + 0 ] = ( uint8_t ) ( ( ulValue ) >> 24 ); \
+ ( (uint8_t*)( pxBase ) ) [ offsetof( xType, xField ) + 1 ] = ( uint8_t ) ( ( ( ulValue ) >> 16 ) & 0xff ); \
+ ( (uint8_t*)( pxBase ) ) [ offsetof( xType, xField ) + 2 ] = ( uint8_t ) ( ( ( ulValue ) >> 8 ) & 0xff ); \
+ ( (uint8_t*)( pxBase ) ) [ offsetof( xType, xField ) + 3 ] = ( uint8_t ) ( ( ulValue ) & 0xff ); \
+}
+
+#define vFlip_16( left, right ) \
+ do { \
+ uint16_t tmp = (left); \
+ (left) = (right); \
+ (right) = tmp; \
+ } while (0)
+
+#define vFlip_32( left, right ) \
+ do { \
+ uint32_t tmp = (left); \
+ (left) = (right); \
+ (right) = tmp; \
+ } while (0)
+
+#ifndef ARRAY_SIZE
+ #define ARRAY_SIZE(x) (BaseType_t)(sizeof(x)/sizeof(x)[0])
+#endif
+
+/*
+ * A version of FreeRTOS_GetReleaseNetworkBuffer() that can be called from an
+ * interrupt. If a non zero value is returned, then the calling ISR should
+ * perform a context switch before exiting the ISR.
+ */
+BaseType_t FreeRTOS_ReleaseFreeNetworkBufferFromISR( void );
+
+/*
+ * Create a message that contains a command to initialise the network interface.
+ * This is used during initialisation, and at any time the network interface
+ * goes down thereafter. The network interface hardware driver is responsible
+ * for sending the message that contains the network interface down command/
+ * event.
+ *
+ * Only use the FreeRTOS_NetworkDownFromISR() version if the function is to be
+ * called from an interrupt service routine. If FreeRTOS_NetworkDownFromISR()
+ * returns a non-zero value then a context switch should be performed ebfore
+ * the interrupt is exited.
+ */
+void FreeRTOS_NetworkDown( void );
+BaseType_t FreeRTOS_NetworkDownFromISR( void );
+
+/*
+ * Processes incoming ARP packets.
+ */
+eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame );
+
+/*
+ * Inspect an Ethernet frame to see if it contains data that the stack needs to
+ * process. eProcessBuffer is returned if the frame should be processed by the
+ * stack. eReleaseBuffer is returned if the frame should be discarded.
+ */
+eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer );
+
+/*
+ * Return the checksum generated over xDataLengthBytes from pucNextData.
+ */
+uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes );
+
+/* Socket related private functions. */
+BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort );
+void vNetworkSocketsInit( void );
+
+/*
+ * Returns pdTRUE if the IP task has been created and is initialised. Otherwise
+ * returns pdFALSE.
+ */
+BaseType_t xIPIsNetworkTaskReady( void );
+
+#if( ipconfigUSE_TCP == 1 )
+
+ /*
+ * Actually a user thing, but because xBoundTCPSocketsList, let it do by the
+ * IP-task
+ */
+ void vTCPNetStat( void );
+
+ /*
+ * At least one socket needs to check for timeouts
+ */
+ TickType_t xTCPTimerCheck( BaseType_t xWillSleep );
+
+ /* Every TCP socket has a buffer space just big enough to store
+ the last TCP header received.
+ As a reference of this field may be passed to DMA, force the
+ alignment to 8 bytes. */
+ typedef union
+ {
+ struct
+ {
+ /* Increase the alignment of this union by adding a 64-bit variable. */
+ uint64_t ullAlignmentWord;
+ } a;
+ struct
+ {
+ /* The next field only serves to give 'ucLastPacket' a correct
+ alignment of 8 + 2. See comments in FreeRTOS_IP.h */
+ uint8_t ucFillPacket[ ipconfigPACKET_FILLER_SIZE ];
+ uint8_t ucLastPacket[ sizeof( TCPPacket_t ) ];
+ } u;
+ } LastTCPPacket_t;
+
+ /*
+ * Note that the values of all short and long integers in these structs
+ * are being stored in the native-endian way
+ * Translation should take place when accessing any structure which defines
+ * network packets, such as IPHeader_t and TCPHeader_t
+ */
+ typedef struct TCPSOCKET
+ {
+ uint32_t ulRemoteIP; /* IP address of remote machine */
+ uint16_t usRemotePort; /* Port on remote machine */
+ struct {
+ /* Most compilers do like bit-flags */
+ uint32_t
+ bMssChange : 1, /* This socket has seen a change in MSS */
+ bPassAccept : 1, /* when true, this socket may be returned in a call to accept() */
+ bPassQueued : 1, /* when true, this socket is an orphan until it gets connected
+ * Why an orphan? Because it may not be returned in a accept() call until it
+ * gets the state eESTABLISHED */
+ bReuseSocket : 1, /* When a listening socket gets a connection, do not create a new instance but keep on using it */
+ bCloseAfterSend : 1,/* As soon as the last byte has been transmitted, finalise the connection
+ * Useful in e.g. FTP connections, where the last data bytes are sent along with the FIN flag */
+ bUserShutdown : 1, /* User requesting a graceful shutdown */
+ bCloseRequested : 1,/* Request to finalise the connection */
+ bLowWater : 1, /* high-water level has been reached. Cleared as soon as 'rx-count < lo-water' */
+ bWinChange : 1, /* The value of bLowWater has changed, must send a window update */
+ bSendKeepAlive : 1, /* When this flag is true, a TCP keep-alive message must be send */
+ bWaitKeepAlive : 1, /* When this flag is true, a TCP keep-alive reply is expected */
+ bConnPrepared : 1, /* Connecting socket: Message has been prepared */
+ #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+ bConnPassed : 1, /* Connecting socket: Socket has been passed in a successful select() */
+ #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
+ bFinAccepted : 1, /* This socket has received (or sent) a FIN and accepted it */
+ bFinSent : 1, /* We've sent out a FIN */
+ bFinRecv : 1, /* We've received a FIN from our peer */
+ bFinAcked : 1, /* Our FIN packet has been acked */
+ bFinLast : 1, /* The last ACK (after FIN and FIN+ACK) has been sent or will be sent by the peer */
+ bRxStopped : 1, /* Application asked to temporarily stop reception */
+ bMallocError : 1, /* There was an error allocating a stream */
+ bWinScaling : 1; /* A TCP-Window Scaling option was offered and accepted in the SYN phase. */
+ } bits;
+ uint32_t ulHighestRxAllowed;
+ /* The highest sequence number that we can receive at any moment */
+ uint16_t usTimeout; /* Time (in ticks) after which this socket needs attention */
+ uint16_t usCurMSS; /* Current Maximum Segment Size */
+ uint16_t usInitMSS; /* Initial maximum segment Size */
+ uint16_t usChildCount; /* In case of a listening socket: number of connections on this port number */
+ uint16_t usBacklog; /* In case of a listening socket: maximum number of concurrent connections on this port number */
+ uint8_t ucRepCount; /* Send repeat count, for retransmissions
+ * This counter is separate from the xmitCount in the
+ * TCP win segments */
+ uint8_t ucTCPState; /* TCP state: see eTCP_STATE */
+ struct XSOCKET *pxPeerSocket; /* for server socket: child, for child socket: parent */
+ #if( ipconfigTCP_KEEP_ALIVE == 1 )
+ uint8_t ucKeepRepCount;
+ TickType_t xLastAliveTime;
+ #endif /* ipconfigTCP_KEEP_ALIVE */
+ #if( ipconfigTCP_HANG_PROTECTION == 1 )
+ TickType_t xLastActTime;
+ #endif /* ipconfigTCP_HANG_PROTECTION */
+ size_t uxLittleSpace;
+ size_t uxEnoughSpace;
+ size_t uxRxStreamSize;
+ size_t uxTxStreamSize;
+ StreamBuffer_t *rxStream;
+ StreamBuffer_t *txStream;
+ #if( ipconfigUSE_TCP_WIN == 1 )
+ NetworkBufferDescriptor_t *pxAckMessage;
+ #endif /* ipconfigUSE_TCP_WIN */
+ /* Buffer space to store the last TCP header received. */
+ LastTCPPacket_t xPacket;
+ uint8_t tcpflags; /* TCP flags */
+ #if( ipconfigUSE_TCP_WIN != 0 )
+ uint8_t ucMyWinScaleFactor;
+ uint8_t ucPeerWinScaleFactor;
+ #endif
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ FOnTCPReceive_t pxHandleReceive; /*
+ * In case of a TCP socket:
+ * typedef void (* FOnTCPReceive_t) (Socket_t xSocket, void *pData, size_t xLength );
+ */
+ FOnTCPSent_t pxHandleSent;
+ FOnConnected_t pxHandleConnected; /* Actually type: typedef void (* FOnConnected_t) (Socket_t xSocket, BaseType_t ulConnected ); */
+ #endif /* ipconfigUSE_CALLBACKS */
+ uint32_t ulWindowSize; /* Current Window size advertised by peer */
+ uint32_t ulRxCurWinSize; /* Constantly changing: this is the current size available for data reception */
+ size_t uxRxWinSize; /* Fixed value: size of the TCP reception window */
+ size_t uxTxWinSize; /* Fixed value: size of the TCP transmit window */
+
+ TCPWindow_t xTCPWindow;
+ } IPTCPSocket_t;
+
+#endif /* ipconfigUSE_TCP */
+
+typedef struct UDPSOCKET
+{
+ List_t xWaitingPacketsList; /* Incoming packets */
+ #if( ipconfigUDP_MAX_RX_PACKETS > 0 )
+ UBaseType_t uxMaxPackets; /* Protection: limits the number of packets buffered per socket */
+ #endif /* ipconfigUDP_MAX_RX_PACKETS */
+ #if( ipconfigUSE_CALLBACKS == 1 )
+ FOnUDPReceive_t pxHandleReceive; /*
+ * In case of a UDP socket:
+ * typedef void (* FOnUDPReceive_t) (Socket_t xSocket, void *pData, size_t xLength, struct freertos_sockaddr *pxAddr );
+ */
+ FOnUDPSent_t pxHandleSent;
+ #endif /* ipconfigUSE_CALLBACKS */
+} IPUDPSocket_t;
+
+typedef enum eSOCKET_EVENT {
+ eSOCKET_RECEIVE = 0x0001,
+ eSOCKET_SEND = 0x0002,
+ eSOCKET_ACCEPT = 0x0004,
+ eSOCKET_CONNECT = 0x0008,
+ eSOCKET_BOUND = 0x0010,
+ eSOCKET_CLOSED = 0x0020,
+ eSOCKET_INTR = 0x0040,
+ eSOCKET_ALL = 0x007F,
+} eSocketEvent_t;
+
+typedef struct XSOCKET
+{
+ EventBits_t xEventBits;
+ EventGroupHandle_t xEventGroup;
+
+ ListItem_t xBoundSocketListItem; /* Used to reference the socket from a bound sockets list. */
+ TickType_t xReceiveBlockTime; /* if recv[to] is called while no data is available, wait this amount of time. Unit in clock-ticks */
+ TickType_t xSendBlockTime; /* if send[to] is called while there is not enough space to send, wait this amount of time. Unit in clock-ticks */
+
+ uint16_t usLocalPort; /* Local port on this machine */
+ uint8_t ucSocketOptions;
+ uint8_t ucProtocol; /* choice of FREERTOS_IPPROTO_UDP/TCP */
+ #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
+ SemaphoreHandle_t pxUserSemaphore;
+ #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
+ #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+ struct xSOCKET_SET *pxSocketSet;
+ /* User may indicate which bits are interesting for this socket. */
+ EventBits_t xSelectBits;
+ /* These bits indicate the events which have actually occurred.
+ They are maintained by the IP-task */
+ EventBits_t xSocketBits;
+ #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
+ /* TCP/UDP specific fields: */
+ /* Before accessing any member of this structure, it should be confirmed */
+ /* that the protocol corresponds with the type of structure */
+
+ union
+ {
+ IPUDPSocket_t xUDP;
+ #if( ipconfigUSE_TCP == 1 )
+ IPTCPSocket_t xTCP;
+ /* Make sure that xTCP is 8-bytes aligned by
+ declaring a 64-bit variable in the same union */
+ uint64_t ullTCPAlignment;
+ #endif /* ipconfigUSE_TCP */
+ } u;
+} FreeRTOS_Socket_t;
+
+#if( ipconfigUSE_TCP == 1 )
+ /*
+ * Lookup a TCP socket, using a multiple matching: both port numbers and
+ * return IP address.
+ */
+ FreeRTOS_Socket_t *pxTCPSocketLookup( uint32_t ulLocalIP, UBaseType_t uxLocalPort, uint32_t ulRemoteIP, UBaseType_t uxRemotePort );
+
+#endif /* ipconfigUSE_TCP */
+
+/*
+ * Look up a local socket by finding a match with the local port.
+ */
+FreeRTOS_Socket_t *pxUDPSocketLookup( UBaseType_t uxLocalPort );
+
+/*
+ * Called when the application has generated a UDP packet to send.
+ */
+void vProcessGeneratedUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
+
+/*
+ * Calculate the upper-layer checksum
+ * Works both for UDP, ICMP and TCP packages
+ * bOut = true: checksum will be set in outgoing packets
+ * bOut = false: checksum will be calculated for incoming packets
+ * returning 0xffff means: checksum was correct
+ */
+uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, BaseType_t xOutgoingPacket );
+
+/*
+ * An Ethernet frame has been updated (maybe it was an ARP request or a PING
+ * request?) and is to be sent back to its source.
+ */
+void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer, BaseType_t xReleaseAfterSend );
+
+/*
+ * The internal version of bind()
+ * If 'ulInternal' is true, it is called by the driver
+ * The TCP driver needs to bind a socket at the moment a listening socket
+ * creates a new connected socket
+ */
+BaseType_t vSocketBind( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr * pxAddress, size_t uxAddressLength, BaseType_t xInternal );
+
+/*
+ * Internal function to add streaming data to a TCP socket. If ulIn == true,
+ * data will be added to the rxStream, otherwise to the tXStream. Normally data
+ * will be written with ulOffset == 0, meaning: at the end of the FIFO. When
+ * packet come in out-of-order, an offset will be used to put it in front and
+ * the head will not change yet.
+ */
+int32_t lTCPAddRxdata( FreeRTOS_Socket_t *pxSocket, size_t uxOffset, const uint8_t *pcData, uint32_t ulByteCount );
+
+/*
+ * Currently called for any important event.
+ */
+void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * Some helping function, their meaning should be clear
+ */
+static portINLINE uint32_t ulChar2u32 (const uint8_t *apChr);
+static portINLINE uint32_t ulChar2u32 (const uint8_t *apChr)
+{
+ return ( ( ( uint32_t )apChr[0] ) << 24) |
+ ( ( ( uint32_t )apChr[1] ) << 16) |
+ ( ( ( uint32_t )apChr[2] ) << 8) |
+ ( ( ( uint32_t )apChr[3] ) );
+}
+
+static portINLINE uint16_t usChar2u16 (const uint8_t *apChr);
+static portINLINE uint16_t usChar2u16 (const uint8_t *apChr)
+{
+ return ( uint16_t )
+ ( ( ( ( uint32_t )apChr[0] ) << 8) |
+ ( ( ( uint32_t )apChr[1] ) ) );
+}
+
+/* Check a single socket for retransmissions and timeouts */
+BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket );
+
+BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket );
+
+/* Defined in FreeRTOS_Sockets.c
+ * Close a socket
+ */
+void *vSocketClose( FreeRTOS_Socket_t *pxSocket );
+
+/*
+ * Send the event eEvent to the IP task event queue, using a block time of
+ * zero. Return pdPASS if the message was sent successfully, otherwise return
+ * pdFALSE.
+*/
+BaseType_t xSendEventToIPTask( eIPEvent_t eEvent );
+
+/*
+ * The same as above, but a struct as a parameter, containing:
+ * eIPEvent_t eEventType;
+ * void *pvData;
+ */
+BaseType_t xSendEventStructToIPTask( const IPStackEvent_t *pxEvent, TickType_t xTimeout );
+
+/*
+ * Returns a pointer to the original NetworkBuffer from a pointer to a UDP
+ * payload buffer.
+ */
+NetworkBufferDescriptor_t *pxUDPPayloadBuffer_to_NetworkBuffer( void *pvBuffer );
+
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ /*
+ * For the case where the network driver passes a buffer directly to a DMA
+ * descriptor, this function can be used to translate a 'network buffer' to
+ * a 'network buffer descriptor'.
+ */
+ NetworkBufferDescriptor_t *pxPacketBuffer_to_NetworkBuffer( const void *pvBuffer );
+#endif
+
+/*
+ * Internal: Sets a new state for a TCP socket and performs the necessary
+ * actions like calling a OnConnected handler to notify the socket owner.
+ */
+#if( ipconfigUSE_TCP == 1 )
+ void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState );
+#endif /* ipconfigUSE_TCP */
+
+/*_RB_ Should this be part of the public API? */
+void FreeRTOS_netstat( void );
+
+/* Returns pdTRUE is this function is called from the IP-task */
+BaseType_t xIsCallingFromIPTask( void );
+
+#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
+
+typedef struct xSOCKET_SET
+{
+ EventGroupHandle_t xSelectGroup;
+ BaseType_t bApiCalled; /* True if the API was calling the private vSocketSelect */
+ FreeRTOS_Socket_t *pxSocket;
+} SocketSelect_t;
+
+extern void vSocketSelect( SocketSelect_t *pxSocketSelect );
+
+#endif /* ipconfigSUPPORT_SELECT_FUNCTION */
+
+void vIPSetDHCPTimerEnableState( BaseType_t xEnableState );
+void vIPReloadDHCPTimer( uint32_t ulLeaseTime );
+#if( ipconfigDNS_USE_CALLBACKS != 0 )
+ void vIPReloadDNSTimer( uint32_t ulCheckTime );
+ void vIPSetDnsTimerEnableState( BaseType_t xEnableState );
+#endif
+
+/* Send the network-up event and start the ARP timer. */
+void vIPNetworkUpCalls( void );
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* FREERTOS_IP_PRIVATE_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h
new file mode 100644
index 000000000..87fb7bba3
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h
@@ -0,0 +1,420 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef FREERTOS_SOCKETS_H
+#define FREERTOS_SOCKETS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Standard includes. */
+#include <string.h>
+
+/* Application level configuration options. */
+#include "FreeRTOSIPConfig.h"
+
+#ifndef FREERTOS_IP_CONFIG_H
+ #error FreeRTOSIPConfig.h has not been included yet
+#endif
+
+/* Event bit definitions are required by the select functions. */
+#include "event_groups.h"
+
+#ifndef INC_FREERTOS_H
+ #error FreeRTOS.h must be included before FreeRTOS_Sockets.h.
+#endif
+
+#ifndef INC_TASK_H
+ #ifndef TASK_H /* For compatibility with older FreeRTOS versions. */
+ #error The FreeRTOS header file task.h must be included before FreeRTOS_Sockets.h.
+ #endif
+#endif
+
+/* Assigned to an Socket_t variable when the socket is not valid, probably
+because it could not be created. */
+#define FREERTOS_INVALID_SOCKET ( ( void * ) ~0U )
+
+/* API function error values. As errno is supported, the FreeRTOS sockets
+functions return error codes rather than just a pass or fail indication. */
+/* HT: Extended the number of error codes, gave them positive values and if possible
+the corresponding found in errno.h
+In case of an error, API's will still return negative numbers, e.g.
+ return -pdFREERTOS_ERRNO_EWOULDBLOCK;
+in case an operation would block */
+
+/* The following defines are obsolete, please use -pdFREERTOS_ERRNO_Exxx */
+
+#define FREERTOS_SOCKET_ERROR ( -1 )
+#define FREERTOS_EWOULDBLOCK ( - pdFREERTOS_ERRNO_EWOULDBLOCK )
+#define FREERTOS_EINVAL ( - pdFREERTOS_ERRNO_EINVAL )
+#define FREERTOS_EADDRNOTAVAIL ( - pdFREERTOS_ERRNO_EADDRNOTAVAIL )
+#define FREERTOS_EADDRINUSE ( - pdFREERTOS_ERRNO_EADDRINUSE )
+#define FREERTOS_ENOBUFS ( - pdFREERTOS_ERRNO_ENOBUFS )
+#define FREERTOS_ENOPROTOOPT ( - pdFREERTOS_ERRNO_ENOPROTOOPT )
+#define FREERTOS_ECLOSED ( - pdFREERTOS_ERRNO_ENOTCONN )
+
+/* Values for the parameters to FreeRTOS_socket(), inline with the Berkeley
+standard. See the documentation of FreeRTOS_socket() for more information. */
+#define FREERTOS_AF_INET ( 2 )
+#define FREERTOS_AF_INET6 ( 10 )
+#define FREERTOS_SOCK_DGRAM ( 2 )
+#define FREERTOS_IPPROTO_UDP ( 17 )
+
+#define FREERTOS_SOCK_STREAM ( 1 )
+#define FREERTOS_IPPROTO_TCP ( 6 )
+/* IP packet of type "Any local network"
+ * can be used in stead of TCP for testing with sockets in raw mode
+ */
+#define FREERTOS_IPPROTO_USR_LAN ( 63 )
+
+/* A bit value that can be passed into the FreeRTOS_sendto() function as part of
+the flags parameter. Setting the FREERTOS_ZERO_COPY in the flags parameter
+indicates that the zero copy interface is being used. See the documentation for
+FreeRTOS_sockets() for more information. */
+#define FREERTOS_ZERO_COPY ( 1 )
+
+/* Values that can be passed in the option name parameter of calls to
+FreeRTOS_setsockopt(). */
+#define FREERTOS_SO_RCVTIMEO ( 0 ) /* Used to set the receive time out. */
+#define FREERTOS_SO_SNDTIMEO ( 1 ) /* Used to set the send time out. */
+#define FREERTOS_SO_UDPCKSUM_OUT ( 2 ) /* Used to turn the use of the UDP checksum by a socket on or off. This also doubles as part of an 8-bit bitwise socket option. */
+#if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
+ #define FREERTOS_SO_SET_SEMAPHORE ( 3 ) /* Used to set a user's semaphore */
+#endif
+#define FREERTOS_SO_SNDBUF ( 4 ) /* Set the size of the send buffer (TCP only) */
+#define FREERTOS_SO_RCVBUF ( 5 ) /* Set the size of the receive buffer (TCP only) */
+
+#if ipconfigUSE_CALLBACKS == 1
+#define FREERTOS_SO_TCP_CONN_HANDLER ( 6 ) /* Install a callback for (dis) connection events. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
+#define FREERTOS_SO_TCP_RECV_HANDLER ( 7 ) /* Install a callback for receiving TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
+#define FREERTOS_SO_TCP_SENT_HANDLER ( 8 ) /* Install a callback for sending TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
+#define FREERTOS_SO_UDP_RECV_HANDLER ( 9 ) /* Install a callback for receiving UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
+#define FREERTOS_SO_UDP_SENT_HANDLER ( 10 ) /* Install a callback for sending UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
+#endif /* ipconfigUSE_CALLBACKS */
+
+#define FREERTOS_SO_REUSE_LISTEN_SOCKET ( 11 ) /* When a listening socket gets connected, do not create a new one but re-use it */
+#define FREERTOS_SO_CLOSE_AFTER_SEND ( 12 ) /* As soon as the last byte has been transmitted, finalise the connection */
+#define FREERTOS_SO_WIN_PROPERTIES ( 13 ) /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */
+#define FREERTOS_SO_SET_FULL_SIZE ( 14 ) /* Refuse to send packets smaller than MSS */
+
+#define FREERTOS_SO_STOP_RX ( 15 ) /* Tempoarily hold up reception, used by streaming client */
+
+#if( ipconfigUDP_MAX_RX_PACKETS > 0 )
+ #define FREERTOS_SO_UDP_MAX_RX_PACKETS ( 16 ) /* This option helps to limit the maximum number of packets a UDP socket will buffer */
+#endif
+
+#define FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET ( 0x80 ) /* For internal use only, but also part of an 8-bit bitwise value. */
+#define FREERTOS_FRAGMENTED_PACKET ( 0x40 ) /* For internal use only, but also part of an 8-bit bitwise value. */
+
+/* Values for flag for FreeRTOS_shutdown(). */
+#define FREERTOS_SHUT_RD ( 0 ) /* Not really at this moment, just for compatibility of the interface */
+#define FREERTOS_SHUT_WR ( 1 )
+#define FREERTOS_SHUT_RDWR ( 2 )
+
+/* Values for flag for FreeRTOS_recv(). */
+#define FREERTOS_MSG_OOB ( 2 ) /* process out-of-band data */
+#define FREERTOS_MSG_PEEK ( 4 ) /* peek at incoming message */
+#define FREERTOS_MSG_DONTROUTE ( 8 ) /* send without using routing tables */
+#define FREERTOS_MSG_DONTWAIT ( 16 ) /* Can be used with recvfrom(), sendto(), recv(), and send(). */
+
+typedef struct xWIN_PROPS {
+ /* Properties of the Tx buffer and Tx window */
+ int32_t lTxBufSize; /* Unit: bytes */
+ int32_t lTxWinSize; /* Unit: MSS */
+
+ /* Properties of the Rx buffer and Rx window */
+ int32_t lRxBufSize; /* Unit: bytes */
+ int32_t lRxWinSize; /* Unit: MSS */
+} WinProperties_t;
+
+/* For compatibility with the expected Berkeley sockets naming. */
+#define socklen_t uint32_t
+
+/* For this limited implementation, only two members are required in the
+Berkeley style sockaddr structure. */
+struct freertos_sockaddr
+{
+ /* _HT_ On 32- and 64-bit architectures, the addition of the two uint8_t
+ fields doesn't make the structure bigger, due to alignment.
+ The fields are inserted as a preparation for IPv6. */
+
+ /* sin_len and sin_family not used in the IPv4-only release. */
+ uint8_t sin_len; /* length of this structure. */
+ uint8_t sin_family; /* FREERTOS_AF_INET. */
+ uint16_t sin_port;
+ uint32_t sin_addr;
+};
+
+#if ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN
+
+ #define FreeRTOS_inet_addr_quick( ucOctet0, ucOctet1, ucOctet2, ucOctet3 ) \
+ ( ( ( ( uint32_t ) ( ucOctet3 ) ) << 24UL ) | \
+ ( ( ( uint32_t ) ( ucOctet2 ) ) << 16UL ) | \
+ ( ( ( uint32_t ) ( ucOctet1 ) ) << 8UL ) | \
+ ( ( uint32_t ) ( ucOctet0 ) ) )
+
+ #define FreeRTOS_inet_ntoa( ulIPAddress, pucBuffer ) \
+ sprintf( ( char * ) ( pucBuffer ), "%u.%u.%u.%u", \
+ ( ( unsigned ) ( ( ulIPAddress ) & 0xffUL ) ), \
+ ( ( unsigned ) ( ( ( ulIPAddress ) >> 8 ) & 0xffUL ) ), \
+ ( ( unsigned ) ( ( ( ulIPAddress ) >> 16 ) & 0xffUL ) ),\
+ ( ( unsigned ) ( ( ulIPAddress ) >> 24 ) ) )
+
+#else /* ipconfigBYTE_ORDER */
+
+ #define FreeRTOS_inet_addr_quick( ucOctet0, ucOctet1, ucOctet2, ucOctet3 ) \
+ ( ( ( ( uint32_t ) ( ucOctet0 ) ) << 24UL ) | \
+ ( ( ( uint32_t ) ( ucOctet1 ) ) << 16UL ) | \
+ ( ( ( uint32_t ) ( ucOctet2 ) ) << 8UL ) | \
+ ( ( uint32_t ) ( ucOctet3 ) ) )
+
+ #define FreeRTOS_inet_ntoa( ulIPAddress, pucBuffer ) \
+ sprintf( ( char * ) ( pucBuffer ), "%u.%u.%u.%u", \
+ ( ( unsigned ) ( ( ulIPAddress ) >> 24 ) ), \
+ ( ( unsigned ) ( ( ( ulIPAddress ) >> 16 ) & 0xffUL ) ),\
+ ( ( unsigned ) ( ( ( ulIPAddress ) >> 8 ) & 0xffUL ) ), \
+ ( ( unsigned ) ( ( ulIPAddress ) & 0xffUL ) ) )
+
+#endif /* ipconfigBYTE_ORDER */
+
+/* The socket type itself. */
+typedef void *Socket_t;
+
+/* The SocketSet_t type is the equivalent to the fd_set type used by the
+Berkeley API. */
+typedef void *SocketSet_t;
+
+/**
+ * FULL, UP-TO-DATE AND MAINTAINED REFERENCE DOCUMENTATION FOR ALL THESE
+ * FUNCTIONS IS AVAILABLE ON THE FOLLOWING URL:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FreeRTOS_TCP_API_Functions.html
+ */
+Socket_t FreeRTOS_socket( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol );
+int32_t FreeRTOS_recvfrom( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength );
+int32_t FreeRTOS_sendto( Socket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, BaseType_t xFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength );
+BaseType_t FreeRTOS_bind( Socket_t xSocket, struct freertos_sockaddr *pxAddress, socklen_t xAddressLength );
+
+/* function to get the local address and IP port */
+size_t FreeRTOS_GetLocalAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress );
+
+/* Made available when ipconfigETHERNET_DRIVER_FILTERS_PACKETS is set to 1. */
+BaseType_t xPortHasUDPSocket( uint16_t usPortNr );
+
+#if ipconfigUSE_TCP == 1
+
+BaseType_t FreeRTOS_connect( Socket_t xClientSocket, struct freertos_sockaddr *pxAddress, socklen_t xAddressLength );
+BaseType_t FreeRTOS_listen( Socket_t xSocket, BaseType_t xBacklog );
+BaseType_t FreeRTOS_recv( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags );
+BaseType_t FreeRTOS_send( Socket_t xSocket, const void *pvBuffer, size_t uxDataLength, BaseType_t xFlags );
+Socket_t FreeRTOS_accept( Socket_t xServerSocket, struct freertos_sockaddr *pxAddress, socklen_t *pxAddressLength );
+BaseType_t FreeRTOS_shutdown (Socket_t xSocket, BaseType_t xHow);
+
+#if( ipconfigSUPPORT_SIGNALS != 0 )
+ /* Send a signal to the task which is waiting for a given socket. */
+ BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket );
+
+ /* Send a signal to the task which reads from this socket (FromISR
+ version). */
+ BaseType_t FreeRTOS_SignalSocketFromISR( Socket_t xSocket, BaseType_t *pxHigherPriorityTaskWoken );
+#endif /* ipconfigSUPPORT_SIGNALS */
+
+/* Return the remote address and IP port. */
+BaseType_t FreeRTOS_GetRemoteAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress );
+
+/* returns pdTRUE if TCP socket is connected */
+BaseType_t FreeRTOS_issocketconnected( Socket_t xSocket );
+
+/* returns the actual size of MSS being used */
+BaseType_t FreeRTOS_mss( Socket_t xSocket );
+
+/* for internal use only: return the connection status */
+BaseType_t FreeRTOS_connstatus( Socket_t xSocket );
+
+/* Returns the number of bytes that may be added to txStream */
+BaseType_t FreeRTOS_maywrite( Socket_t xSocket );
+
+/*
+ * Two helper functions, mostly for testing
+ * rx_size returns the number of bytes available in the Rx buffer
+ * tx_space returns the free space in the Tx buffer
+ */
+BaseType_t FreeRTOS_rx_size( Socket_t xSocket );
+BaseType_t FreeRTOS_tx_space( Socket_t xSocket );
+BaseType_t FreeRTOS_tx_size( Socket_t xSocket );
+
+/* Returns the number of outstanding bytes in txStream. */
+/* The function FreeRTOS_outstanding() was already implemented
+FreeRTOS_tx_size(). */
+#define FreeRTOS_outstanding( xSocket ) FreeRTOS_tx_size( xSocket )
+
+/* Returns the number of bytes in the socket's rxStream. */
+/* The function FreeRTOS_recvcount() was already implemented
+FreeRTOS_rx_size(). */
+#define FreeRTOS_recvcount( xSocket ) FreeRTOS_rx_size( xSocket )
+
+/*
+ * For advanced applications only:
+ * Get a direct pointer to the circular transmit buffer.
+ * '*pxLength' will contain the number of bytes that may be written.
+ */
+uint8_t *FreeRTOS_get_tx_head( Socket_t xSocket, BaseType_t *pxLength );
+
+#endif /* ipconfigUSE_TCP */
+
+/*
+ * Connect / disconnect handler for a TCP socket
+ * For example:
+ * static void vMyConnectHandler (Socket_t xSocket, BaseType_t ulConnected)
+ * {
+ * }
+ * F_TCP_UDP_Handler_t xHnd = { vMyConnectHandler };
+ * FreeRTOS_setsockopt( sock, 0, FREERTOS_SO_TCP_CONN_HANDLER, ( void * ) &xHnd, sizeof( xHnd ) );
+ */
+
+typedef void (* FOnConnected_t )( Socket_t /* xSocket */, BaseType_t /* ulConnected */ );
+
+/*
+ * Reception handler for a TCP socket
+ * A user-proved function will be called on reception of a message
+ * If the handler returns a positive number, the messages will not be stored
+ * For example:
+ * static BaseType_t xOnTCPReceive( Socket_t xSocket, void * pData, size_t xLength )
+ * {
+ * // handle the message
+ * return 1;
+ * }
+ * F_TCP_UDP_Handler_t xHand = { xOnTCPReceive };
+ * FreeRTOS_setsockopt( sock, 0, FREERTOS_SO_TCP_RECV_HANDLER, ( void * ) &xHand, sizeof( xHand ) );
+ */
+typedef BaseType_t (* FOnTCPReceive_t )( Socket_t /* xSocket */, void * /* pData */, size_t /* xLength */ );
+typedef void (* FOnTCPSent_t )( Socket_t /* xSocket */, size_t /* xLength */ );
+
+/*
+ * Reception handler for a UDP socket
+ * A user-proved function will be called on reception of a message
+ * If the handler returns a positive number, the messages will not be stored
+ */
+typedef BaseType_t (* FOnUDPReceive_t ) (Socket_t /* xSocket */, void * /* pData */, size_t /* xLength */,
+ const struct freertos_sockaddr * /* pxFrom */, const struct freertos_sockaddr * /* pxDest */ );
+typedef void (* FOnUDPSent_t )( Socket_t /* xSocket */, size_t /* xLength */ );
+
+
+typedef union xTCP_UDP_HANDLER
+{
+ FOnConnected_t pxOnTCPConnected; /* FREERTOS_SO_TCP_CONN_HANDLER */
+ FOnTCPReceive_t pxOnTCPReceive; /* FREERTOS_SO_TCP_RECV_HANDLER */
+ FOnTCPSent_t pxOnTCPSent; /* FREERTOS_SO_TCP_SENT_HANDLER */
+ FOnUDPReceive_t pxOnUDPReceive; /* FREERTOS_SO_UDP_RECV_HANDLER */
+ FOnUDPSent_t pxOnUDPSent; /* FREERTOS_SO_UDP_SENT_HANDLER */
+} F_TCP_UDP_Handler_t;
+
+BaseType_t FreeRTOS_setsockopt( Socket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength );
+BaseType_t FreeRTOS_closesocket( Socket_t xSocket );
+uint32_t FreeRTOS_gethostbyname( const char *pcHostName );
+uint32_t FreeRTOS_inet_addr( const char * pcIPAddress );
+
+/*
+ * For the web server: borrow the circular Rx buffer for inspection
+ * HTML driver wants to see if a sequence of 13/10/13/10 is available
+ */
+const struct xSTREAM_BUFFER *FreeRTOS_get_rx_buf( Socket_t xSocket );
+
+void FreeRTOS_netstat( void );
+
+#if ipconfigSUPPORT_SELECT_FUNCTION == 1
+
+ /* For FD_SET and FD_CLR, a combination of the following bits can be used: */
+
+ typedef enum eSELECT_EVENT {
+ eSELECT_READ = 0x0001,
+ eSELECT_WRITE = 0x0002,
+ eSELECT_EXCEPT = 0x0004,
+ eSELECT_INTR = 0x0008,
+ eSELECT_ALL = 0x000F,
+ /* Reserved for internal use: */
+ eSELECT_CALL_IP = 0x0010,
+ /* end */
+ } eSelectEvent_t;
+
+ SocketSet_t FreeRTOS_CreateSocketSet( void );
+ void FreeRTOS_DeleteSocketSet( SocketSet_t xSocketSet );
+ void FreeRTOS_FD_SET( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xBitsToSet );
+ void FreeRTOS_FD_CLR( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xBitsToClear );
+ EventBits_t FreeRTOS_FD_ISSET( Socket_t xSocket, SocketSet_t xSocketSet );
+ BaseType_t FreeRTOS_select( SocketSet_t xSocketSet, TickType_t xBlockTimeTicks );
+
+#endif /* ipconfigSUPPORT_SELECT_FUNCTION */
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* FREERTOS_SOCKETS_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h
new file mode 100644
index 000000000..9b84f9732
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h
@@ -0,0 +1,288 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*
+ * FreeRTOS_Stream_Buffer.h
+ *
+ * A cicular character buffer
+ * An implementation of a circular buffer without a length field
+ * If LENGTH defines the size of the buffer, a maximum of (LENGT-1) bytes can be stored
+ * In order to add or read data from the buffer, memcpy() will be called at most 2 times
+ */
+
+#ifndef FREERTOS_STREAM_BUFFER_H
+#define FREERTOS_STREAM_BUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct xSTREAM_BUFFER {
+ volatile size_t uxTail; /* next item to read */
+ volatile size_t uxMid; /* iterator within the valid items */
+ volatile size_t uxHead; /* next position store a new item */
+ volatile size_t uxFront; /* iterator within the free space */
+ size_t LENGTH; /* const value: number of reserved elements */
+ uint8_t ucArray[ sizeof( size_t ) ];
+} StreamBuffer_t;
+
+static portINLINE void vStreamBufferClear( StreamBuffer_t *pxBuffer );
+static portINLINE void vStreamBufferClear( StreamBuffer_t *pxBuffer )
+{
+ /* Make the circular buffer empty */
+ pxBuffer->uxHead = 0u;
+ pxBuffer->uxTail = 0u;
+ pxBuffer->uxFront = 0u;
+ pxBuffer->uxMid = 0u;
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE size_t uxStreamBufferSpace( const StreamBuffer_t *pxBuffer, const size_t uxLower, const size_t uxUpper );
+static portINLINE size_t uxStreamBufferSpace( const StreamBuffer_t *pxBuffer, const size_t uxLower, const size_t uxUpper )
+{
+/* Returns the space between uxLower and uxUpper, which equals to the distance minus 1 */
+size_t uxCount;
+
+ uxCount = pxBuffer->LENGTH + uxUpper - uxLower - 1u;
+ if( uxCount >= pxBuffer->LENGTH )
+ {
+ uxCount -= pxBuffer->LENGTH;
+ }
+
+ return uxCount;
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE size_t uxStreamBufferDistance( const StreamBuffer_t *pxBuffer, const size_t uxLower, const size_t uxUpper );
+static portINLINE size_t uxStreamBufferDistance( const StreamBuffer_t *pxBuffer, const size_t uxLower, const size_t uxUpper )
+{
+/* Returns the distance between uxLower and uxUpper */
+size_t uxCount;
+
+ uxCount = pxBuffer->LENGTH + uxUpper - uxLower;
+ if ( uxCount >= pxBuffer->LENGTH )
+ {
+ uxCount -= pxBuffer->LENGTH;
+ }
+
+ return uxCount;
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE size_t uxStreamBufferGetSpace( const StreamBuffer_t *pxBuffer );
+static portINLINE size_t uxStreamBufferGetSpace( const StreamBuffer_t *pxBuffer )
+{
+/* Returns the number of items which can still be added to uxHead
+before hitting on uxTail */
+size_t uxHead = pxBuffer->uxHead;
+size_t uxTail = pxBuffer->uxTail;
+
+ return uxStreamBufferSpace( pxBuffer, uxHead, uxTail );
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE size_t uxStreamBufferFrontSpace( const StreamBuffer_t *pxBuffer );
+static portINLINE size_t uxStreamBufferFrontSpace( const StreamBuffer_t *pxBuffer )
+{
+/* Distance between uxFront and uxTail
+or the number of items which can still be added to uxFront,
+before hitting on uxTail */
+
+size_t uxFront = pxBuffer->uxFront;
+size_t uxTail = pxBuffer->uxTail;
+
+ return uxStreamBufferSpace( pxBuffer, uxFront, uxTail );
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE size_t uxStreamBufferGetSize( const StreamBuffer_t *pxBuffer );
+static portINLINE size_t uxStreamBufferGetSize( const StreamBuffer_t *pxBuffer )
+{
+/* Returns the number of items which can be read from uxTail
+before reaching uxHead */
+size_t uxHead = pxBuffer->uxHead;
+size_t uxTail = pxBuffer->uxTail;
+
+ return uxStreamBufferDistance( pxBuffer, uxTail, uxHead );
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE size_t uxStreamBufferMidSpace( const StreamBuffer_t *pxBuffer );
+static portINLINE size_t uxStreamBufferMidSpace( const StreamBuffer_t *pxBuffer )
+{
+/* Returns the distance between uxHead and uxMid */
+size_t uxHead = pxBuffer->uxHead;
+size_t uxMid = pxBuffer->uxMid;
+
+ return uxStreamBufferDistance( pxBuffer, uxMid, uxHead );
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE void vStreamBufferMoveMid( StreamBuffer_t *pxBuffer, size_t uxCount );
+static portINLINE void vStreamBufferMoveMid( StreamBuffer_t *pxBuffer, size_t uxCount )
+{
+/* Increment uxMid, but no further than uxHead */
+size_t uxSize = uxStreamBufferMidSpace( pxBuffer );
+
+ if( uxCount > uxSize )
+ {
+ uxCount = uxSize;
+ }
+ pxBuffer->uxMid += uxCount;
+ if( pxBuffer->uxMid >= pxBuffer->LENGTH )
+ {
+ pxBuffer->uxMid -= pxBuffer->LENGTH;
+ }
+}
+/*-----------------------------------------------------------*/
+static portINLINE BaseType_t xStreamBufferIsEmpty( const StreamBuffer_t *pxBuffer );
+static portINLINE BaseType_t xStreamBufferIsEmpty( const StreamBuffer_t *pxBuffer )
+{
+BaseType_t xReturn;
+
+ /* True if no item is available */
+ if( pxBuffer->uxHead == pxBuffer->uxTail )
+ {
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE BaseType_t xStreamBufferIsFull( const StreamBuffer_t *pxBuffer );
+static portINLINE BaseType_t xStreamBufferIsFull( const StreamBuffer_t *pxBuffer )
+{
+ /* True if the available space equals zero. */
+ return ( BaseType_t ) ( uxStreamBufferGetSpace( pxBuffer ) == 0u );
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE BaseType_t xStreamBufferLessThenEqual( const StreamBuffer_t *pxBuffer, const size_t uxLeft, const size_t uxRight );
+static portINLINE BaseType_t xStreamBufferLessThenEqual( const StreamBuffer_t *pxBuffer, const size_t uxLeft, const size_t uxRight )
+{
+BaseType_t xReturn;
+size_t uxTail = pxBuffer->uxTail;
+
+ /* Returns true if ( uxLeft < uxRight ) */
+ if( ( uxLeft < uxTail ) ^ ( uxRight < uxTail ) )
+ {
+ if( uxRight < uxTail )
+ {
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+ }
+ else
+ {
+ if( uxLeft <= uxRight )
+ {
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+ }
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE size_t uxStreamBufferGetPtr( StreamBuffer_t *pxBuffer, uint8_t **ppucData );
+static portINLINE size_t uxStreamBufferGetPtr( StreamBuffer_t *pxBuffer, uint8_t **ppucData )
+{
+size_t uxNextTail = pxBuffer->uxTail;
+size_t uxSize = uxStreamBufferGetSize( pxBuffer );
+
+ *ppucData = pxBuffer->ucArray + uxNextTail;
+
+ return FreeRTOS_min_uint32( uxSize, pxBuffer->LENGTH - uxNextTail );
+}
+
+/*
+ * Add bytes to a stream buffer.
+ *
+ * pxBuffer - The buffer to which the bytes will be added.
+ * uxOffset - If uxOffset > 0, data will be written at an offset from uxHead
+ * while uxHead will not be moved yet.
+ * pucData - A pointer to the data to be added.
+ * uxCount - The number of bytes to add.
+ */
+size_t uxStreamBufferAdd( StreamBuffer_t *pxBuffer, size_t uxOffset, const uint8_t *pucData, size_t uxCount );
+
+/*
+ * Read bytes from a stream buffer.
+ *
+ * pxBuffer - The buffer from which the bytes will be read.
+ * uxOffset - Can be used to read data located at a certain offset from 'uxTail'.
+ * pucData - A pointer to the buffer into which data will be read.
+ * uxMaxCount - The number of bytes to read.
+ * xPeek - If set to pdTRUE the data will remain in the buffer.
+ */
+size_t uxStreamBufferGet( StreamBuffer_t *pxBuffer, size_t uxOffset, uint8_t *pucData, size_t uxMaxCount, BaseType_t xPeek );
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* !defined( FREERTOS_STREAM_BUFFER_H ) */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h
new file mode 100644
index 000000000..3d51640b4
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h
@@ -0,0 +1,112 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef FREERTOS_TCP_IP_H
+#define FREERTOS_TCP_IP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer );
+
+typedef enum eTCP_STATE {
+ /* Comments about the TCP states are borrowed from the very useful
+ * Wiki page:
+ * http://en.wikipedia.org/wiki/Transmission_Control_Protocol */
+ eCLOSED = 0u, /* 0 (server + client) no connection state at all. */
+ eTCP_LISTEN, /* 1 (server) waiting for a connection request
+ from any remote TCP and port. */
+ eCONNECT_SYN, /* 2 (client) internal state: socket wants to send
+ a connect */
+ eSYN_FIRST, /* 3 (server) Just created, must ACK the SYN request. */
+ eSYN_RECEIVED, /* 4 (server) waiting for a confirming connection request
+ acknowledgement after having both received and sent a connection request. */
+ eESTABLISHED, /* 5 (server + client) an open connection, data received can be
+ delivered to the user. The normal state for the data transfer phase of the connection. */
+ eFIN_WAIT_1, /* 6 (server + client) waiting for a connection termination request from the remote TCP,
+ or an acknowledgement of the connection termination request previously sent. */
+ eFIN_WAIT_2, /* 7 (server + client) waiting for a connection termination request from the remote TCP. */
+ eCLOSE_WAIT, /* 8 (server + client) waiting for a connection termination request from the local user. */
+ eCLOSING, /* (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */
+ eLAST_ACK, /* 9 (server + client) waiting for an acknowledgement of the connection termination request
+ previously sent to the remote TCP
+ (which includes an acknowledgement of its connection termination request). */
+ eTIME_WAIT, /* 10 (either server or client) waiting for enough time to pass to be sure the remote TCP received the
+ acknowledgement of its connection termination request. [According to RFC 793 a connection can
+ stay in TIME-WAIT for a maximum of four minutes known as a MSL (maximum segment lifetime).] */
+} eIPTCPState_t;
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* FREERTOS_TCP_IP_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h
new file mode 100644
index 000000000..b55c69722
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h
@@ -0,0 +1,253 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*
+ * FreeRTOS_TCP_WIN.c
+ * Module which handles the TCP windowing schemes for FreeRTOS-PLUS-TCP
+ */
+
+#ifndef FREERTOS_TCP_WIN_H
+#define FREERTOS_TCP_WIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern BaseType_t xTCPWindowLoggingLevel;
+
+typedef struct xTCPTimer
+{
+ uint32_t ulBorn;
+} TCPTimer_t;
+
+typedef struct xTCP_SEGMENT
+{
+ uint32_t ulSequenceNumber; /* The sequence number of the first byte in this packet */
+ int32_t lMaxLength; /* Maximum space, number of bytes which can be stored in this segment */
+ int32_t lDataLength; /* Actual number of bytes */
+ int32_t lStreamPos; /* reference to the [t|r]xStream of the socket */
+ TCPTimer_t xTransmitTimer; /* saves a timestamp at the moment this segment gets transmitted (TX only) */
+ union
+ {
+ struct
+ {
+ uint32_t
+ ucTransmitCount : 8,/* Number of times the segment has been transmitted, used to calculate the RTT */
+ ucDupAckCount : 8, /* Counts the number of times that a higher segment was ACK'd. After 3 times a Fast Retransmission takes place */
+ bOutstanding : 1, /* It the peer's turn, we're just waiting for an ACK */
+ bAcked : 1, /* This segment has been acknowledged */
+ bIsForRx : 1; /* pdTRUE if segment is used for reception */
+ } bits;
+ uint32_t ulFlags;
+ } u;
+#if( ipconfigUSE_TCP_WIN != 0 )
+ struct xLIST_ITEM xQueueItem; /* TX only: segments can be linked in one of three queues: xPriorityQueue, xTxQueue, and xWaitQueue */
+ struct xLIST_ITEM xListItem; /* With this item the segment can be connected to a list, depending on who is owning it */
+#endif
+} TCPSegment_t;
+
+typedef struct xTCP_WINSIZE
+{
+ uint32_t ulRxWindowLength;
+ uint32_t ulTxWindowLength;
+} TCPWinSize_t;
+
+/*
+ * If TCP time-stamps are being used, they will occupy 12 bytes in
+ * each packet, and thus the message space will become smaller
+ */
+/* Keep this as a multiple of 4 */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
+ #define ipSIZE_TCP_OPTIONS ( 16u + 12u )
+ #else
+ #define ipSIZE_TCP_OPTIONS 16u
+ #endif
+#else
+ #if ipconfigUSE_TCP_TIMESTAMPS == 1
+ #define ipSIZE_TCP_OPTIONS ( 12u + 12u )
+ #else
+ #define ipSIZE_TCP_OPTIONS 12u
+ #endif
+#endif
+
+/*
+ * Every TCP connection owns a TCP window for the administration of all packets
+ * It owns two sets of segment descriptors, incoming and outgoing
+ */
+typedef struct xTCP_WINDOW
+{
+ union
+ {
+ struct
+ {
+ uint32_t
+ bHasInit : 1, /* The window structure has been initialised */
+ bSendFullSize : 1, /* May only send packets with a size equal to MSS (for optimisation) */
+ bTimeStamps : 1; /* Socket is supposed to use TCP time-stamps. This depends on the */
+ } bits; /* party which opens the connection */
+ uint32_t ulFlags;
+ } u;
+ TCPWinSize_t xSize;
+ struct
+ {
+ uint32_t ulFirstSequenceNumber; /* Logging & debug: the first segment received/sent in this connection
+ * for Tx: initial send sequence number (ISS)
+ * for Rx: initial receive sequence number (IRS) */
+ uint32_t ulCurrentSequenceNumber;/* Tx/Rx: the oldest sequence number not yet confirmed, also SND.UNA / RCV.NXT
+ * In other words: the sequence number of the left side of the sliding window */
+ uint32_t ulFINSequenceNumber; /* The sequence number which carried the FIN flag */
+ uint32_t ulHighestSequenceNumber;/* Sequence number of the right-most byte + 1 */
+#if( ipconfigUSE_TCP_TIMESTAMPS == 1 )
+ uint32_t ulTimeStamp; /* The value of the TCP timestamp, transmitted or received */
+#endif
+ } rx, tx;
+ uint32_t ulOurSequenceNumber; /* The SEQ number we're sending out */
+ uint32_t ulUserDataLength; /* Number of bytes in Rx buffer which may be passed to the user, after having received a 'missing packet' */
+ uint32_t ulNextTxSequenceNumber; /* The sequence number given to the next byte to be added for transmission */
+ int32_t lSRTT; /* Smoothed Round Trip Time, it may increment quickly and it decrements slower */
+ uint8_t ucOptionLength; /* Number of valid bytes in ulOptionsData[] */
+#if( ipconfigUSE_TCP_WIN == 1 )
+ List_t xPriorityQueue; /* Priority queue: segments which must be sent immediately */
+ List_t xTxQueue; /* Transmit queue: segments queued for transmission */
+ List_t xWaitQueue; /* Waiting queue: outstanding segments */
+ TCPSegment_t *pxHeadSegment; /* points to a segment which has not been transmitted and it's size is still growing (user data being added) */
+ uint32_t ulOptionsData[ipSIZE_TCP_OPTIONS/sizeof(uint32_t)]; /* Contains the options we send out */
+ List_t xTxSegments; /* A linked list of all transmission segments, sorted on sequence number */
+ List_t xRxSegments; /* A linked list of reception segments, order depends on sequence of arrival */
+#else
+ /* For tiny TCP, there is only 1 outstanding TX segment */
+ TCPSegment_t xTxSegment; /* Priority queue */
+#endif
+ uint16_t usOurPortNumber; /* Mostly for debugging/logging: our TCP port number */
+ uint16_t usPeerPortNumber; /* debugging/logging: the peer's TCP port number */
+ uint16_t usMSS; /* Current accepted MSS */
+ uint16_t usMSSInit; /* MSS as configured by the socket owner */
+} TCPWindow_t;
+
+
+/*=============================================================================
+ *
+ * Creation and destruction
+ *
+ *=============================================================================*/
+
+/* Create and initialize a window */
+void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength,
+ uint32_t ulTxWindowLength, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS );
+
+/* Destroy a window (always returns NULL)
+ * It will free some resources: a collection of segments */
+void vTCPWindowDestroy( TCPWindow_t *pxWindow );
+
+/* Initialize a window */
+void vTCPWindowInit( TCPWindow_t *pxWindow, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS );
+
+/*=============================================================================
+ *
+ * Rx functions
+ *
+ *=============================================================================*/
+
+/* if true may be passed directly to user (segment expected and window is empty)
+ * But pxWindow->ackno should always be used to set "BUF->ackno" */
+int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace );
+
+/* When lTCPWindowRxCheck returned false, please call store for this unexpected data */
+BaseType_t xTCPWindowRxStore( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength );
+
+/* This function will be called as soon as a FIN is received. It will return true
+ * if there are no 'open' reception segments */
+BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow );
+
+/* _HT_ Temporary function for testing/debugging
+ * Not used at this moment */
+void vTCPWinShowSegments( TCPWindow_t *pxWindow, BaseType_t bForRx );
+
+/*=============================================================================
+ *
+ * Tx functions
+ *
+ *=============================================================================*/
+
+/* Adds data to the Tx-window */
+int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax );
+
+/* Check data to be sent and calculate the time period we may sleep */
+BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay );
+
+/* See if anything is left to be sent
+ * Function will be called when a FIN has been received. Only when the TX window is clean,
+ * it will return pdTRUE */
+BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow );
+
+/* Fetches data to be sent.
+ * apPos will point to a location with the circular data buffer: txStream */
+uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition );
+
+/* Receive a normal ACK */
+uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber );
+
+/* Receive a SACK option */
+uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast );
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* FREERTOS_TCP_WIN_H */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h
new file mode 100644
index 000000000..5f704afee
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h
@@ -0,0 +1,88 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef FREERTOS_UDP_IP_H
+#define FREERTOS_UDP_IP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Application level configuration options. */
+#include "FreeRTOSIPConfig.h"
+#include "FreeRTOSIPConfigDefaults.h"
+#include "IPTraceMacroDefaults.h"
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* FREERTOS_UDP_IP_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h
new file mode 100644
index 000000000..a8b0bc0b4
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h
@@ -0,0 +1,122 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef FREERTOS_ERRNO_TCP
+#define FREERTOS_ERRNO_TCP
+
+/* The following definitions will be included in the core FreeRTOS code in
+future versions of FreeRTOS - hence the 'pd' (ProjDefs) prefix - at which time
+this file will be removed. */
+
+/* The following errno values are used by FreeRTOS+ components, not FreeRTOS
+itself. */
+
+/* For future compatibility (see comment above), check the definitions have not
+already been made. */
+#ifndef pdFREERTOS_ERRNO_NONE
+ #define pdFREERTOS_ERRNO_NONE 0 /* No errors */
+ #define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */
+ #define pdFREERTOS_ERRNO_EINTR 4 /* Interrupted system call */
+ #define pdFREERTOS_ERRNO_EIO 5 /* I/O error */
+ #define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */
+ #define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */
+ #define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */
+ #define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */
+ #define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */
+ #define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */
+ #define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */
+ #define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */
+ #define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */
+ #define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */
+ #define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */
+ #define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */
+ #define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */
+ #define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */
+ #define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */
+ #define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */
+ #define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */
+ #define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */
+ #define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */
+ #define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */
+ #define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */
+ #define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */
+ #define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */
+ #define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
+ #define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */
+ #define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */
+ #define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */
+ #define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */
+ #define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */
+ #define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */
+ #define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */
+ #define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */
+ #define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */
+ #define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */
+ #define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */
+ #define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */
+
+ /* The following endian values are used by FreeRTOS+ components, not FreeRTOS
+ itself. */
+ #define pdFREERTOS_LITTLE_ENDIAN 0
+ #define pdFREERTOS_BIG_ENDIAN 1
+
+#endif /* pdFREERTOS_ERRNO_NONE */
+
+#endif /* FREERTOS_ERRNO_TCP */
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h
new file mode 100644
index 000000000..3e30722ee
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h
@@ -0,0 +1,225 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* This file provides default (empty) implementations for any IP trace macros
+that are not defined by the user. See
+http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Trace.html */
+
+#ifndef UDP_TRACE_MACRO_DEFAULTS_H
+#define UDP_TRACE_MACRO_DEFAULTS_H
+
+#ifndef iptraceNETWORK_DOWN
+ #define iptraceNETWORK_DOWN()
+#endif
+
+#ifndef iptraceNETWORK_BUFFER_RELEASED
+ #define iptraceNETWORK_BUFFER_RELEASED( pxBufferAddress )
+#endif
+
+#ifndef iptraceNETWORK_BUFFER_OBTAINED
+ #define iptraceNETWORK_BUFFER_OBTAINED( pxBufferAddress )
+#endif
+
+#ifndef iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR
+ #define iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxBufferAddress )
+#endif
+
+#ifndef iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER
+ #define iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER()
+#endif
+
+#ifndef iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR
+ #define iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR()
+#endif
+
+#ifndef iptraceCREATING_ARP_REQUEST
+ #define iptraceCREATING_ARP_REQUEST( ulIPAddress )
+#endif
+
+#ifndef iptraceARP_TABLE_ENTRY_WILL_EXPIRE
+ #define iptraceARP_TABLE_ENTRY_WILL_EXPIRE( ulIPAddress )
+#endif
+
+#ifndef iptraceARP_TABLE_ENTRY_EXPIRED
+ #define iptraceARP_TABLE_ENTRY_EXPIRED( ulIPAddress )
+#endif
+
+#ifndef iptraceARP_TABLE_ENTRY_CREATED
+ #define iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, ucMACAddress )
+#endif
+
+#ifndef iptraceSENDING_UDP_PACKET
+ #define iptraceSENDING_UDP_PACKET( ulIPAddress )
+#endif
+
+#ifndef iptracePACKET_DROPPED_TO_GENERATE_ARP
+ #define iptracePACKET_DROPPED_TO_GENERATE_ARP( ulIPAddress )
+#endif
+
+#ifndef iptraceICMP_PACKET_RECEIVED
+ #define iptraceICMP_PACKET_RECEIVED()
+#endif
+
+#ifndef iptraceSENDING_PING_REPLY
+ #define iptraceSENDING_PING_REPLY( ulIPAddress )
+#endif
+
+#ifndef traceARP_PACKET_RECEIVED
+ #define traceARP_PACKET_RECEIVED()
+#endif
+
+#ifndef iptracePROCESSING_RECEIVED_ARP_REPLY
+ #define iptracePROCESSING_RECEIVED_ARP_REPLY( ulIPAddress )
+#endif
+
+#ifndef iptraceSENDING_ARP_REPLY
+ #define iptraceSENDING_ARP_REPLY( ulIPAddress )
+#endif
+
+#ifndef iptraceFAILED_TO_CREATE_SOCKET
+ #define iptraceFAILED_TO_CREATE_SOCKET()
+#endif
+
+#ifndef iptraceFAILED_TO_CREATE_EVENT_GROUP
+ #define iptraceFAILED_TO_CREATE_EVENT_GROUP()
+#endif
+
+#ifndef iptraceRECVFROM_DISCARDING_BYTES
+ #define iptraceRECVFROM_DISCARDING_BYTES( xNumberOfBytesDiscarded )
+#endif
+
+#ifndef iptraceETHERNET_RX_EVENT_LOST
+ #define iptraceETHERNET_RX_EVENT_LOST()
+#endif
+
+#ifndef iptraceSTACK_TX_EVENT_LOST
+ #define iptraceSTACK_TX_EVENT_LOST( xEvent )
+#endif
+
+#ifndef iptraceNETWORK_EVENT_RECEIVED
+ #define iptraceNETWORK_EVENT_RECEIVED( eEvent )
+#endif
+
+#ifndef iptraceBIND_FAILED
+ #define iptraceBIND_FAILED( xSocket, usPort )
+#endif
+
+#ifndef iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS
+ #define iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( ulIPAddress )
+#endif
+
+#ifndef iptraceSENDING_DHCP_DISCOVER
+ #define iptraceSENDING_DHCP_DISCOVER()
+#endif
+
+#ifndef iptraceSENDING_DHCP_REQUEST
+ #define iptraceSENDING_DHCP_REQUEST()
+#endif
+
+#ifndef iptraceDHCP_SUCCEDEED
+ #define iptraceDHCP_SUCCEDEED( address )
+#endif
+
+#ifndef iptraceNETWORK_INTERFACE_TRANSMIT
+ #define iptraceNETWORK_INTERFACE_TRANSMIT()
+#endif
+
+#ifndef iptraceNETWORK_INTERFACE_RECEIVE
+ #define iptraceNETWORK_INTERFACE_RECEIVE()
+#endif
+
+#ifndef iptraceSENDING_DNS_REQUEST
+ #define iptraceSENDING_DNS_REQUEST()
+#endif
+
+#ifndef iptraceWAITING_FOR_TX_DMA_DESCRIPTOR
+ #define iptraceWAITING_FOR_TX_DMA_DESCRIPTOR()
+#endif
+
+#ifndef ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS
+ #define ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS 0
+#endif
+
+#ifndef iptraceFAILED_TO_NOTIFY_SELECT_GROUP
+ #define iptraceFAILED_TO_NOTIFY_SELECT_GROUP( xSocket )
+#endif
+
+#ifndef pvPortMallocSocket
+ #define pvPortMallocSocket(xSize) pvPortMalloc( ( xSize ) )
+#endif
+
+#ifndef iptraceRECVFROM_TIMEOUT
+ #define iptraceRECVFROM_TIMEOUT()
+#endif
+
+#ifndef iptraceRECVFROM_INTERRUPTED
+ #define iptraceRECVFROM_INTERRUPTED()
+#endif
+
+#ifndef iptraceNO_BUFFER_FOR_SENDTO
+ #define iptraceNO_BUFFER_FOR_SENDTO()
+#endif
+
+#ifndef iptraceSENDTO_SOCKET_NOT_BOUND
+ #define iptraceSENDTO_SOCKET_NOT_BOUND()
+#endif
+
+#ifndef iptraceSENDTO_DATA_TOO_LONG
+ #define iptraceSENDTO_DATA_TOO_LONG()
+#endif
+
+#endif /* UDP_TRACE_MACRO_DEFAULTS_H */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h
new file mode 100644
index 000000000..6eeddc875
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h
@@ -0,0 +1,102 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef NETWORK_BUFFER_MANAGEMENT_H
+#define NETWORK_BUFFER_MANAGEMENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* NOTE PUBLIC API FUNCTIONS. */
+BaseType_t xNetworkBuffersInitialise( void );
+NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks );
+NetworkBufferDescriptor_t *pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes );
+void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer );
+BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer );
+uint8_t *pucGetNetworkBuffer( size_t *pxRequestedSizeBytes );
+void vReleaseNetworkBuffer( uint8_t *pucEthernetBuffer );
+
+/* Get the current number of free network buffers. */
+UBaseType_t uxGetNumberOfFreeNetworkBuffers( void );
+
+/* Get the lowest number of free network buffers. */
+UBaseType_t uxGetMinimumFreeNetworkBuffers( void );
+
+/* Copy a network buffer into a bigger buffer. */
+NetworkBufferDescriptor_t *pxDuplicateNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer,
+ BaseType_t xNewLength);
+
+/* Increase the size of a Network Buffer.
+In case BufferAllocation_2.c is used, the new space must be allocated. */
+NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer,
+ size_t xNewSizeBytes );
+
+#if ipconfigTCP_IP_SANITY
+ /*
+ * Check if an address is a valid pointer to a network descriptor
+ * by looking it up in the array of network descriptors
+ */
+ UBaseType_t bIsValidNetworkDescriptor (const NetworkBufferDescriptor_t * pxDesc);
+ BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t *pxDescr );
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* NETWORK_BUFFER_MANAGEMENT_H */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h
new file mode 100644
index 000000000..65e235d88
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h
@@ -0,0 +1,76 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef NETWORK_INTERFACE_H
+#define NETWORK_INTERFACE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* NOTE PUBLIC API FUNCTIONS. */
+BaseType_t xNetworkInterfaceInitialise( void );
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t xReleaseAfterSend );
+void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] );
+BaseType_t xGetPhyLinkStatus( void );
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* NETWORK_INTERFACE_H */
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c
new file mode 100644
index 000000000..fb860893d
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c
@@ -0,0 +1,455 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/******************************************************************************
+ *
+ * See the following web page for essential buffer allocation scheme usage and
+ * configuration details:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
+ *
+ ******************************************************************************/
+
+/* Standard includes. */
+#include <stdint.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_IP_Private.h"
+#include "NetworkInterface.h"
+#include "NetworkBufferManagement.h"
+
+/* For an Ethernet interrupt to be able to obtain a network buffer there must
+be at least this number of buffers available. */
+#define baINTERRUPT_BUFFER_GET_THRESHOLD ( 3 )
+
+/* A list of free (available) NetworkBufferDescriptor_t structures. */
+static List_t xFreeBuffersList;
+
+/* Some statistics about the use of buffers. */
+static UBaseType_t uxMinimumFreeNetworkBuffers = 0u;
+
+/* Declares the pool of NetworkBufferDescriptor_t structures that are available
+to the system. All the network buffers referenced from xFreeBuffersList exist
+in this array. The array is not accessed directly except during initialisation,
+when the xFreeBuffersList is filled (as all the buffers are free when the system
+is booted). */
+static NetworkBufferDescriptor_t xNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
+
+/* This constant is defined as true to let FreeRTOS_TCP_IP.c know that the
+network buffers have constant size, large enough to hold the biggest Ethernet
+packet. No resizing will be done. */
+const BaseType_t xBufferAllocFixedSize = pdTRUE;
+
+/* The semaphore used to obtain network buffers. */
+static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
+
+#if( ipconfigTCP_IP_SANITY != 0 )
+ static char cIsLow = pdFALSE;
+ UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );
+#else
+ static UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );
+#endif /* ipconfigTCP_IP_SANITY */
+
+static void prvShowWarnings( void );
+
+/* The user can define their own ipconfigBUFFER_ALLOC_LOCK() and
+ipconfigBUFFER_ALLOC_UNLOCK() macros, especially for use form an ISR. If these
+are not defined then default them to call the normal enter/exit critical
+section macros. */
+#if !defined( ipconfigBUFFER_ALLOC_LOCK )
+
+ #define ipconfigBUFFER_ALLOC_INIT( ) do {} while (0)
+ #define ipconfigBUFFER_ALLOC_LOCK_FROM_ISR() \
+ UBaseType_t uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \
+ {
+
+ #define ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR() \
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
+ }
+
+ #define ipconfigBUFFER_ALLOC_LOCK() taskENTER_CRITICAL()
+ #define ipconfigBUFFER_ALLOC_UNLOCK() taskEXIT_CRITICAL()
+
+#endif /* ipconfigBUFFER_ALLOC_LOCK */
+
+/*-----------------------------------------------------------*/
+
+#if( ipconfigTCP_IP_SANITY != 0 )
+
+ /* HT: SANITY code will be removed as soon as the library is stable
+ * and and ready to become public
+ * Function below gives information about the use of buffers */
+ #define WARN_LOW ( 2 )
+ #define WARN_HIGH ( ( 5 * ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) / 10 )
+
+#endif /* ipconfigTCP_IP_SANITY */
+
+/*-----------------------------------------------------------*/
+
+#if( ipconfigTCP_IP_SANITY != 0 )
+
+ BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t *pxDescr )
+ {
+ return ( bIsValidNetworkDescriptor( pxDescr ) != 0 ) &&
+ ( listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxDescr->xBufferListItem ) ) != 0 );
+ }
+ /*-----------------------------------------------------------*/
+
+ static void prvShowWarnings( void )
+ {
+ UBaseType_t uxCount = uxGetNumberOfFreeNetworkBuffers( );
+ if( ( ( cIsLow == 0 ) && ( uxCount <= WARN_LOW ) ) || ( ( cIsLow != 0 ) && ( uxCount >= WARN_HIGH ) ) )
+ {
+ cIsLow = !cIsLow;
+ FreeRTOS_debug_printf( ( "*** Warning *** %s %lu buffers left\n", cIsLow ? "only" : "now", uxCount ) );
+ }
+ }
+ /*-----------------------------------------------------------*/
+
+ UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc )
+ {
+ uint32_t offset = ( uint32_t ) ( ((const char *)pxDesc) - ((const char *)xNetworkBuffers) );
+ if( ( offset >= sizeof( xNetworkBuffers ) ) ||
+ ( ( offset % sizeof( xNetworkBuffers[0] ) ) != 0 ) )
+ return pdFALSE;
+ return (UBaseType_t) (pxDesc - xNetworkBuffers) + 1;
+ }
+ /*-----------------------------------------------------------*/
+
+#else
+ static UBaseType_t bIsValidNetworkDescriptor (const NetworkBufferDescriptor_t * pxDesc)
+ {
+ ( void ) pxDesc;
+ return ( UBaseType_t ) pdTRUE;
+ }
+ /*-----------------------------------------------------------*/
+
+ static void prvShowWarnings( void )
+ {
+ }
+ /*-----------------------------------------------------------*/
+
+#endif /* ipconfigTCP_IP_SANITY */
+
+BaseType_t xNetworkBuffersInitialise( void )
+{
+BaseType_t xReturn, x;
+
+ /* Only initialise the buffers and their associated kernel objects if they
+ have not been initialised before. */
+ if( xNetworkBufferSemaphore == NULL )
+ {
+ /* In case alternative locking is used, the mutexes can be initialised
+ here */
+ ipconfigBUFFER_ALLOC_INIT();
+
+ xNetworkBufferSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
+ configASSERT( xNetworkBufferSemaphore );
+
+ if( xNetworkBufferSemaphore != NULL )
+ {
+ vListInitialise( &xFreeBuffersList );
+
+ /* Initialise all the network buffers. The buffer storage comes
+ from the network interface, and different hardware has different
+ requirements. */
+ vNetworkInterfaceAllocateRAMToBuffers( xNetworkBuffers );
+ for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
+ {
+ /* Initialise and set the owner of the buffer list items. */
+ vListInitialiseItem( &( xNetworkBuffers[ x ].xBufferListItem ) );
+ listSET_LIST_ITEM_OWNER( &( xNetworkBuffers[ x ].xBufferListItem ), &xNetworkBuffers[ x ] );
+
+ /* Currently, all buffers are available for use. */
+ vListInsert( &xFreeBuffersList, &( xNetworkBuffers[ x ].xBufferListItem ) );
+ }
+
+ uxMinimumFreeNetworkBuffers = ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
+ }
+ }
+
+ if( xNetworkBufferSemaphore == NULL )
+ {
+ xReturn = pdFAIL;
+ }
+ else
+ {
+ xReturn = pdPASS;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
+{
+NetworkBufferDescriptor_t *pxReturn = NULL;
+BaseType_t xInvalid = pdFALSE;
+UBaseType_t uxCount;
+
+ /* The current implementation only has a single size memory block, so
+ the requested size parameter is not used (yet). */
+ ( void ) xRequestedSizeBytes;
+
+ if( xNetworkBufferSemaphore != NULL )
+ {
+ /* If there is a semaphore available, there is a network buffer
+ available. */
+ if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
+ {
+ /* Protect the structure as it is accessed from tasks and
+ interrupts. */
+ ipconfigBUFFER_ALLOC_LOCK();
+ {
+ pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
+
+ if( ( bIsValidNetworkDescriptor( pxReturn ) != pdFALSE_UNSIGNED ) &&
+ listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxReturn->xBufferListItem ) ) )
+ {
+ uxListRemove( &( pxReturn->xBufferListItem ) );
+ }
+ else
+ {
+ xInvalid = pdTRUE;
+ }
+ }
+ ipconfigBUFFER_ALLOC_UNLOCK();
+
+ if( xInvalid == pdTRUE )
+ {
+ /* _RB_ Can printf() be called from an interrupt? (comment
+ above says this can be called from an interrupt too) */
+ /* _HT_ The function shall not be called from an ISR. Comment
+ was indeed misleading. Hopefully clear now?
+ So the printf()is OK here. */
+ FreeRTOS_debug_printf( ( "pxGetNetworkBufferWithDescriptor: INVALID BUFFER: %p (valid %lu)\n",
+ pxReturn, bIsValidNetworkDescriptor( pxReturn ) ) );
+ pxReturn = NULL;
+ }
+ else
+ {
+ /* Reading UBaseType_t, no critical section needed. */
+ uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
+
+ /* For stats, latch the lowest number of network buffers since
+ booting. */
+ if( uxMinimumFreeNetworkBuffers > uxCount )
+ {
+ uxMinimumFreeNetworkBuffers = uxCount;
+ }
+
+ pxReturn->xDataLength = xRequestedSizeBytes;
+
+ #if( ipconfigTCP_IP_SANITY != 0 )
+ {
+ prvShowWarnings();
+ }
+ #endif /* ipconfigTCP_IP_SANITY */
+
+ #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
+ {
+ /* make sure the buffer is not linked */
+ pxReturn->pxNextBuffer = NULL;
+ }
+ #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
+
+ if( xTCPWindowLoggingLevel > 3 )
+ {
+ FreeRTOS_debug_printf( ( "BUF_GET[%ld]: %p (%p)\n",
+ bIsValidNetworkDescriptor( pxReturn ),
+ pxReturn, pxReturn->pucEthernetBuffer ) );
+ }
+ }
+ iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
+ }
+ else
+ {
+ iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
+ }
+ }
+
+ return pxReturn;
+}
+/*-----------------------------------------------------------*/
+
+NetworkBufferDescriptor_t *pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes )
+{
+NetworkBufferDescriptor_t *pxReturn = NULL;
+
+ /* The current implementation only has a single size memory block, so
+ the requested size parameter is not used (yet). */
+ ( void ) xRequestedSizeBytes;
+
+ /* If there is a semaphore available then there is a buffer available, but,
+ as this is called from an interrupt, only take a buffer if there are at
+ least baINTERRUPT_BUFFER_GET_THRESHOLD buffers remaining. This prevents,
+ to a certain degree at least, a rapidly executing interrupt exhausting
+ buffer and in so doing preventing tasks from continuing. */
+ if( uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) xNetworkBufferSemaphore ) > ( UBaseType_t ) baINTERRUPT_BUFFER_GET_THRESHOLD )
+ {
+ if( xSemaphoreTakeFromISR( xNetworkBufferSemaphore, NULL ) == pdPASS )
+ {
+ /* Protect the structure as it is accessed from tasks and interrupts. */
+ ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();
+ {
+ pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
+ uxListRemove( &( pxReturn->xBufferListItem ) );
+ }
+ ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();
+
+ iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxReturn );
+ }
+ }
+
+ if( pxReturn == NULL )
+ {
+ iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR();
+ }
+
+ return pxReturn;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer )
+{
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+
+ /* Ensure the buffer is returned to the list of free buffers before the
+ counting semaphore is 'given' to say a buffer is available. */
+ ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();
+ {
+ vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
+ }
+ ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();
+
+ xSemaphoreGiveFromISR( xNetworkBufferSemaphore, &xHigherPriorityTaskWoken );
+ iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
+
+ return xHigherPriorityTaskWoken;
+}
+/*-----------------------------------------------------------*/
+
+void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
+{
+BaseType_t xListItemAlreadyInFreeList;
+
+ if( bIsValidNetworkDescriptor( pxNetworkBuffer ) == pdFALSE_UNSIGNED )
+ {
+ FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: Invalid buffer %p\n", pxNetworkBuffer ) );
+ return ;
+ }
+ /* Ensure the buffer is returned to the list of free buffers before the
+ counting semaphore is 'given' to say a buffer is available. */
+ ipconfigBUFFER_ALLOC_LOCK();
+ {
+ {
+ xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
+
+ if( xListItemAlreadyInFreeList == pdFALSE )
+ {
+ vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
+ }
+ }
+ }
+ ipconfigBUFFER_ALLOC_UNLOCK();
+
+ if( xListItemAlreadyInFreeList )
+ {
+ FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: %p ALREADY RELEASED (now %lu)\n",
+ pxNetworkBuffer, uxGetNumberOfFreeNetworkBuffers( ) ) );
+ }
+ if( xListItemAlreadyInFreeList == pdFALSE )
+ {
+ xSemaphoreGive( xNetworkBufferSemaphore );
+ prvShowWarnings();
+ if( xTCPWindowLoggingLevel > 3 )
+ FreeRTOS_debug_printf( ( "BUF_PUT[%ld]: %p (%p) (now %lu)\n",
+ bIsValidNetworkDescriptor( pxNetworkBuffer ),
+ pxNetworkBuffer, pxNetworkBuffer->pucEthernetBuffer,
+ uxGetNumberOfFreeNetworkBuffers( ) ) );
+ }
+ iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
+}
+/*-----------------------------------------------------------*/
+
+UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
+{
+ return uxMinimumFreeNetworkBuffers;
+}
+/*-----------------------------------------------------------*/
+
+UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
+{
+ return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
+}
+
+NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )
+{
+ /* In BufferAllocation_1.c all network buffer are allocated with a
+ maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the
+ network buffer. */
+ ( void ) xNewSizeBytes;
+ return pxNetworkBuffer;
+}
+
+/*#endif */ /* ipconfigINCLUDE_TEST_CODE */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c
new file mode 100644
index 000000000..dd438181c
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c
@@ -0,0 +1,410 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/******************************************************************************
+ *
+ * See the following web page for essential buffer allocation scheme usage and
+ * configuration details:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
+ *
+ ******************************************************************************/
+
+/* THIS FILE SHOULD NOT BE USED IF THE PROJECT INCLUDES A MEMORY ALLOCATOR
+THAT WILL FRAGMENT THE HEAP MEMORY. For example, heap_2 must not be used,
+heap_4 can be used. */
+
+
+/* Standard includes. */
+#include <stdint.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_IP_Private.h"
+#include "NetworkInterface.h"
+#include "NetworkBufferManagement.h"
+
+/* The obtained network buffer must be large enough to hold a packet that might
+replace the packet that was requested to be sent. */
+#if ipconfigUSE_TCP == 1
+ #define baMINIMAL_BUFFER_SIZE sizeof( TCPPacket_t )
+#else
+ #define baMINIMAL_BUFFER_SIZE sizeof( ARPPacket_t )
+#endif /* ipconfigUSE_TCP == 1 */
+
+/*_RB_ This is too complex not to have an explanation. */
+#if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+ #define ASSERT_CONCAT_(a, b) a##b
+ #define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
+ #define STATIC_ASSERT(e) \
+ ;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
+
+ STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE );
+#endif
+
+/* A list of free (available) NetworkBufferDescriptor_t structures. */
+static List_t xFreeBuffersList;
+
+/* Some statistics about the use of buffers. */
+static size_t uxMinimumFreeNetworkBuffers;
+
+/* Declares the pool of NetworkBufferDescriptor_t structures that are available
+to the system. All the network buffers referenced from xFreeBuffersList exist
+in this array. The array is not accessed directly except during initialisation,
+when the xFreeBuffersList is filled (as all the buffers are free when the system
+is booted). */
+static NetworkBufferDescriptor_t xNetworkBufferDescriptors[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
+
+/* This constant is defined as false to let FreeRTOS_TCP_IP.c know that the
+network buffers have a variable size: resizing may be necessary */
+const BaseType_t xBufferAllocFixedSize = pdFALSE;
+
+/* The semaphore used to obtain network buffers. */
+static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
+
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkBuffersInitialise( void )
+{
+BaseType_t xReturn, x;
+
+ /* Only initialise the buffers and their associated kernel objects if they
+ have not been initialised before. */
+ if( xNetworkBufferSemaphore == NULL )
+ {
+ xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
+ configASSERT( xNetworkBufferSemaphore );
+ #if ( configQUEUE_REGISTRY_SIZE > 0 )
+ {
+ vQueueAddToRegistry( xNetworkBufferSemaphore, "NetBufSem" );
+ }
+ #endif /* configQUEUE_REGISTRY_SIZE */
+
+ /* If the trace recorder code is included name the semaphore for viewing
+ in FreeRTOS+Trace. */
+ #if( ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 )
+ {
+ extern QueueHandle_t xNetworkEventQueue;
+ vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" );
+ vTraceSetQueueName( xNetworkBufferSemaphore, "NetworkBufferCount" );
+ }
+ #endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */
+
+ if( xNetworkBufferSemaphore != NULL )
+ {
+ vListInitialise( &xFreeBuffersList );
+
+ /* Initialise all the network buffers. No storage is allocated to
+ the buffers yet. */
+ for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
+ {
+ /* Initialise and set the owner of the buffer list items. */
+ xNetworkBufferDescriptors[ x ].pucEthernetBuffer = NULL;
+ vListInitialiseItem( &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
+ listSET_LIST_ITEM_OWNER( &( xNetworkBufferDescriptors[ x ].xBufferListItem ), &xNetworkBufferDescriptors[ x ] );
+
+ /* Currently, all buffers are available for use. */
+ vListInsert( &xFreeBuffersList, &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
+ }
+
+ uxMinimumFreeNetworkBuffers = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
+ }
+ }
+
+ if( xNetworkBufferSemaphore == NULL )
+ {
+ xReturn = pdFAIL;
+ }
+ else
+ {
+ xReturn = pdPASS;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+uint8_t *pucGetNetworkBuffer( size_t *pxRequestedSizeBytes )
+{
+uint8_t *pucEthernetBuffer;
+size_t xSize = *pxRequestedSizeBytes;
+
+ if( xSize < baMINIMAL_BUFFER_SIZE )
+ {
+ /* Buffers must be at least large enough to hold a TCP-packet with
+ headers, or an ARP packet, in case TCP is not included. */
+ xSize = baMINIMAL_BUFFER_SIZE;
+ }
+
+ /* Round up xSize to the nearest multiple of N bytes,
+ where N equals 'sizeof( size_t )'. */
+ if( ( xSize & ( sizeof( size_t ) - 1u ) ) != 0u )
+ {
+ xSize = ( xSize | ( sizeof( size_t ) - 1u ) ) + 1u;
+ }
+ *pxRequestedSizeBytes = xSize;
+
+ /* Allocate a buffer large enough to store the requested Ethernet frame size
+ and a pointer to a network buffer structure (hence the addition of
+ ipBUFFER_PADDING bytes). */
+ pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xSize + ipBUFFER_PADDING );
+ configASSERT( pucEthernetBuffer );
+
+ if( pucEthernetBuffer != NULL )
+ {
+ /* Enough space is left at the start of the buffer to place a pointer to
+ the network buffer structure that references this Ethernet buffer.
+ Return a pointer to the start of the Ethernet buffer itself. */
+ pucEthernetBuffer += ipBUFFER_PADDING;
+ }
+
+ return pucEthernetBuffer;
+}
+/*-----------------------------------------------------------*/
+
+void vReleaseNetworkBuffer( uint8_t *pucEthernetBuffer )
+{
+ /* There is space before the Ethernet buffer in which a pointer to the
+ network buffer that references this Ethernet buffer is stored. Remove the
+ space before freeing the buffer. */
+ if( pucEthernetBuffer != NULL )
+ {
+ pucEthernetBuffer -= ipBUFFER_PADDING;
+ vPortFree( ( void * ) pucEthernetBuffer );
+ }
+}
+/*-----------------------------------------------------------*/
+
+NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
+{
+NetworkBufferDescriptor_t *pxReturn = NULL;
+size_t uxCount;
+
+ if( ( xRequestedSizeBytes != 0u ) && ( xRequestedSizeBytes < ( size_t ) baMINIMAL_BUFFER_SIZE ) )
+ {
+ /* ARP packets can replace application packets, so the storage must be
+ at least large enough to hold an ARP. */
+ xRequestedSizeBytes = baMINIMAL_BUFFER_SIZE;
+ }
+
+ /* Add 2 bytes to xRequestedSizeBytes and round up xRequestedSizeBytes
+ to the nearest multiple of N bytes, where N equals 'sizeof( size_t )'. */
+ xRequestedSizeBytes += 2u;
+ if( ( xRequestedSizeBytes & ( sizeof( size_t ) - 1u ) ) != 0u )
+ {
+ xRequestedSizeBytes = ( xRequestedSizeBytes | ( sizeof( size_t ) - 1u ) ) + 1u;
+ }
+
+ /* If there is a semaphore available, there is a network buffer available. */
+ if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
+ {
+ /* Protect the structure as it is accessed from tasks and interrupts. */
+ taskENTER_CRITICAL();
+ {
+ pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
+ uxListRemove( &( pxReturn->xBufferListItem ) );
+ }
+ taskEXIT_CRITICAL();
+
+ /* Reading UBaseType_t, no critical section needed. */
+ uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
+
+ if( uxMinimumFreeNetworkBuffers > uxCount )
+ {
+ uxMinimumFreeNetworkBuffers = uxCount;
+ }
+
+ /* Allocate storage of exactly the requested size to the buffer. */
+ configASSERT( pxReturn->pucEthernetBuffer == NULL );
+ if( xRequestedSizeBytes > 0 )
+ {
+ /* Extra space is obtained so a pointer to the network buffer can
+ be stored at the beginning of the buffer. */
+ pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytes + ipBUFFER_PADDING );
+
+ if( pxReturn->pucEthernetBuffer == NULL )
+ {
+ /* The attempt to allocate storage for the buffer payload failed,
+ so the network buffer structure cannot be used and must be
+ released. */
+ vReleaseNetworkBufferAndDescriptor( pxReturn );
+ pxReturn = NULL;
+ }
+ else
+ {
+ /* Store a pointer to the network buffer structure in the
+ buffer storage area, then move the buffer pointer on past the
+ stored pointer so the pointer value is not overwritten by the
+ application when the buffer is used. */
+ *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn;
+ pxReturn->pucEthernetBuffer += ipBUFFER_PADDING;
+
+ /* Store the actual size of the allocated buffer, which may be
+ greater than the original requested size. */
+ pxReturn->xDataLength = xRequestedSizeBytes;
+
+ #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
+ {
+ /* make sure the buffer is not linked */
+ pxReturn->pxNextBuffer = NULL;
+ }
+ #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
+ }
+ }
+ else
+ {
+ /* A descriptor is being returned without an associated buffer being
+ allocated. */
+ }
+ }
+
+ if( pxReturn == NULL )
+ {
+ iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
+ }
+ else
+ {
+ iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
+ }
+
+ return pxReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
+{
+BaseType_t xListItemAlreadyInFreeList;
+
+ /* Ensure the buffer is returned to the list of free buffers before the
+ counting semaphore is 'given' to say a buffer is available. Release the
+ storage allocated to the buffer payload. THIS FILE SHOULD NOT BE USED
+ IF THE PROJECT INCLUDES A MEMORY ALLOCATOR THAT WILL FRAGMENT THE HEAP
+ MEMORY. For example, heap_2 must not be used, heap_4 can be used. */
+ vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
+ pxNetworkBuffer->pucEthernetBuffer = NULL;
+
+ taskENTER_CRITICAL();
+ {
+ xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
+
+ if( xListItemAlreadyInFreeList == pdFALSE )
+ {
+ vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ if( xListItemAlreadyInFreeList == pdFALSE )
+ {
+ xSemaphoreGive( xNetworkBufferSemaphore );
+ }
+
+ iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Returns the number of free network buffers
+ */
+UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
+{
+ return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
+}
+/*-----------------------------------------------------------*/
+
+UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
+{
+ return uxMinimumFreeNetworkBuffers;
+}
+/*-----------------------------------------------------------*/
+
+NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )
+{
+size_t xOriginalLength;
+uint8_t *pucBuffer;
+
+ xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING;
+ xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING;
+
+ pucBuffer = pucGetNetworkBuffer( &( xNewSizeBytes ) );
+
+ if( pucBuffer == NULL )
+ {
+ /* In case the allocation fails, return NULL. */
+ pxNetworkBuffer = NULL;
+ }
+ else
+ {
+ pxNetworkBuffer->xDataLength = xNewSizeBytes;
+ if( xNewSizeBytes > xOriginalLength )
+ {
+ xNewSizeBytes = xOriginalLength;
+ }
+
+ memcpy( pucBuffer - ipBUFFER_PADDING, pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING, xNewSizeBytes );
+ vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
+ pxNetworkBuffer->pucEthernetBuffer = pucBuffer;
+ }
+
+ return pxNetworkBuffer;
+}
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h
new file mode 100644
index 000000000..9ce33f4e5
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h
@@ -0,0 +1,78 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*****************************************************************************
+ *
+ * See the following URL for an explanation of this file:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
+ *
+ *****************************************************************************/
+__attribute__( (packed) );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h
new file mode 100644
index 000000000..f9335cb5f
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h
@@ -0,0 +1,80 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*****************************************************************************
+ *
+ * See the following URL for an explanation of this file:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
+ *
+ *****************************************************************************/
+
+/* Nothing to do here. */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h
new file mode 100644
index 000000000..4a4a4ef5d
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h
@@ -0,0 +1,79 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*****************************************************************************
+ *
+ * See the following URL for an explanation of this file:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
+ *
+ *****************************************************************************/
+
+;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h
new file mode 100644
index 000000000..af79f52cb
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h
@@ -0,0 +1,81 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*****************************************************************************
+ *
+ * See the following URL for an explanation of this file:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
+ *
+ *****************************************************************************/
+
+__packed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h
new file mode 100644
index 000000000..5c309204a
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h
@@ -0,0 +1,80 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*****************************************************************************
+ *
+ * See the following URL for an explanation of this file:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
+ *
+ *****************************************************************************/
+
+;
+#pragma pack( pop )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h
new file mode 100644
index 000000000..bca26e7bd
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h
@@ -0,0 +1,79 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*****************************************************************************
+ *
+ * See the following URL for an explanation of this file:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
+ *
+ *****************************************************************************/
+
+#pragma pack( push, 1 )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h
new file mode 100644
index 000000000..da67ba73d
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h
@@ -0,0 +1,86 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*****************************************************************************
+ *
+ * See the following URL for an explanation of this file:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
+ *
+ *****************************************************************************/
+
+
+#ifdef _SH
+ #ifdef __RENESAS__
+ ;
+ #pragma unpack
+ #endif
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h
new file mode 100644
index 000000000..31675a845
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h
@@ -0,0 +1,85 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*****************************************************************************
+ *
+ * See the following URL for an explanation of this file:
+ * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
+ *
+ *****************************************************************************/
+
+
+#ifdef _SH
+ #ifdef __RENESAS__
+ #pragma pack 1
+ #endif
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c
new file mode 100644
index 000000000..7a0da571f
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c
@@ -0,0 +1,680 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.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 "NetworkBufferManagement.h"
+#include "NetworkInterface.h"
+
+/* Some files from the Atmel Software Framework */
+/*_RB_ The SAM4E portable layer has three different header files called gmac.h! */
+#include "instance/gmac.h"
+#include <sysclk.h>
+#include <ethernet_phy.h>
+
+#ifndef BMSR_LINK_STATUS
+ #define BMSR_LINK_STATUS 0x0004 //!< Link status
+#endif
+
+#ifndef PHY_LS_HIGH_CHECK_TIME_MS
+ /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
+ receiving packets. */
+ #define PHY_LS_HIGH_CHECK_TIME_MS 15000
+#endif
+
+#ifndef PHY_LS_LOW_CHECK_TIME_MS
+ /* Check if the LinkSStatus in the PHY is still low every second. */
+ #define PHY_LS_LOW_CHECK_TIME_MS 1000
+#endif
+
+/* Interrupt events to process. Currently only the Rx event is processed
+although code for other events is included to allow for possible future
+expansion. */
+#define EMAC_IF_RX_EVENT 1UL
+#define EMAC_IF_TX_EVENT 2UL
+#define EMAC_IF_ERR_EVENT 4UL
+#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
+
+#define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
+
+#define HZ_PER_MHZ ( 1000000UL )
+
+#ifndef EMAC_MAX_BLOCK_TIME_MS
+ #define EMAC_MAX_BLOCK_TIME_MS 100ul
+#endif
+
+#if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )
+ #error Please define GMAC_USES_TX_CALLBACK as 1
+#endif
+
+#if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+ #warning The EMAC of SAM4E has fixed-size RX buffers so ZERO_COPY_RX is not possible
+#endif
+
+/* Default the size of the stack used by the EMAC deferred handler task to 4x
+the size of the stack used by the idle task - but allow this to be overridden in
+FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
+#ifndef configEMAC_TASK_STACK_SIZE
+ #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
+#endif
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Wait a fixed time for the link status to indicate the network is up.
+ */
+static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
+
+#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
+ void vGMACGenerateChecksum( uint8_t *apBuffer );
+#endif
+
+/*
+ * Called from the ASF GMAC driver.
+ */
+static void prvRxCallback( uint32_t ulStatus );
+static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );
+
+/*
+ * A deferred interrupt handler task that processes GMAC interrupts.
+ */
+static void prvEMACHandlerTask( void *pvParameters );
+
+/*
+ * Initialise the ASF GMAC driver.
+ */
+static BaseType_t prvGMACInit( void );
+
+/*
+ * Try to obtain an Rx packet from the hardware.
+ */
+static uint32_t prvEMACRxPoll( void );
+
+/*-----------------------------------------------------------*/
+
+/* Bit map of outstanding ETH interrupt events for processing. Currently only
+the Rx interrupt is handled, although code is included for other events to
+enable future expansion. */
+static volatile uint32_t ulISREvents;
+
+/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
+static uint32_t ulPHYLinkStatus = 0;
+static volatile BaseType_t xGMACSwitchRequired;
+
+/* ethernet_phy_addr: the address of the PHY in use.
+Atmel was a bit ambiguous about it so the address will be stored
+in this variable, see ethernet_phy.c */
+extern int ethernet_phy_addr;
+
+/* LLMNR multicast address. */
+static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
+
+/* The GMAC object as defined by the ASF drivers. */
+static gmac_device_t gs_gmac_dev;
+
+/* MAC address to use. */
+extern const uint8_t ucMACAddress[ 6 ];
+
+/* Holds the handle of the task used as a deferred interrupt processor. The
+handle is used so direct notifications can be sent to the task for all EMAC/DMA
+related interrupts. */
+TaskHandle_t xEMACTaskHandle = NULL;
+
+static QueueHandle_t xTxBufferQueue;
+int tx_release_count[ 4 ];
+
+/* xTXDescriptorSemaphore is a counting semaphore with
+a maximum count of GMAC_TX_BUFFERS, which is the number of
+DMA TX descriptors. */
+static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * GMAC interrupt handler.
+ */
+void GMAC_Handler(void)
+{
+ xGMACSwitchRequired = pdFALSE;
+
+ /* gmac_handler() may call prvRxCallback() which may change
+ the value of xGMACSwitchRequired. */
+ gmac_handler( &gs_gmac_dev );
+
+ if( xGMACSwitchRequired != pdFALSE )
+ {
+ portEND_SWITCHING_ISR( xGMACSwitchRequired );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvRxCallback( uint32_t ulStatus )
+{
+ if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
+ {
+ /* let the prvEMACHandlerTask know that there was an RX event. */
+ ulISREvents |= EMAC_IF_RX_EVENT;
+ /* Only an RX interrupt can wakeup prvEMACHandlerTask. */
+ vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )
+{
+ if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
+ {
+ /* let the prvEMACHandlerTask know that there was an RX event. */
+ ulISREvents |= EMAC_IF_TX_EVENT;
+
+ vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
+ xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
+ tx_release_count[ 2 ]++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceInitialise( void )
+{
+const TickType_t x5_Seconds = 5000UL;
+
+ if( xEMACTaskHandle == NULL )
+ {
+ prvGMACInit();
+
+ /* Wait at most 5 seconds for a Link Status in the PHY. */
+ xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
+
+ /* The handler task is created at the highest possible priority to
+ ensure the interrupt handler can return directly to it. */
+ xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
+ configASSERT( xEMACTaskHandle );
+ }
+
+ if( xTxBufferQueue == NULL )
+ {
+ xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
+ configASSERT( xTxBufferQueue );
+ }
+
+ if( xTXDescriptorSemaphore == NULL )
+ {
+ xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
+ configASSERT( xTXDescriptorSemaphore );
+ }
+ /* When returning non-zero, the stack will become active and
+ start DHCP (in configured) */
+ return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xGetPhyLinkStatus( void )
+{
+BaseType_t xResult;
+
+ /* This function returns true if the Link Status in the PHY is high. */
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ xResult = pdTRUE;
+ }
+ else
+ {
+ xResult = pdFALSE;
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
+{
+/* Do not wait too long for a free TX DMA buffer. */
+const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
+
+ do {
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
+ {
+ /* Do not attempt to send packets as long as the Link Status is low. */
+ break;
+ }
+ if( xTXDescriptorSemaphore == NULL )
+ {
+ /* Semaphore has not been created yet? */
+ break;
+ }
+ if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
+ {
+ /* Time-out waiting for a free TX descriptor. */
+ tx_release_count[ 3 ]++;
+ break;
+ }
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* Confirm that the pxDescriptor may be kept by the driver. */
+ configASSERT( bReleaseAfterSend != pdFALSE );
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+ gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
+
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* Confirm that the pxDescriptor may be kept by the driver. */
+ bReleaseAfterSend = pdFALSE;
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+ /* Not interested in a call-back after TX. */
+ iptraceNETWORK_INTERFACE_TRANSMIT();
+ } while( 0 );
+
+ if( bReleaseAfterSend != pdFALSE )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxDescriptor );
+ }
+ return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvGMACInit( void )
+{
+uint32_t ncfgr;
+
+ gmac_options_t gmac_option;
+
+ memset( &gmac_option, '\0', sizeof( gmac_option ) );
+ gmac_option.uc_copy_all_frame = 0;
+ gmac_option.uc_no_boardcast = 0;
+ memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) );
+
+ gs_gmac_dev.p_hw = GMAC;
+ gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
+
+ NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
+ NVIC_EnableIRQ( GMAC_IRQn );
+
+ /* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */
+ ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );
+
+ ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
+ ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
+
+ /* The GMAC driver will call a hook prvRxCallback(), which
+ in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */
+ gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );
+ gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address );
+
+ ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
+
+ GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
+
+ return 1;
+}
+/*-----------------------------------------------------------*/
+
+static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
+{
+uint32_t ulValue, ulReturn;
+int rc;
+
+ gmac_enable_management( GMAC, 1 );
+ rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );
+ gmac_enable_management( GMAC, 0 );
+ if( rc == GMAC_OK )
+ {
+ ulReturn = ulValue;
+ }
+ else
+ {
+ ulReturn = 0UL;
+ }
+
+ return ulReturn;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
+{
+TickType_t xStartTime = xTaskGetTickCount();
+TickType_t xEndTime;
+BaseType_t xReturn;
+const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
+
+ for( ;; )
+ {
+ xEndTime = xTaskGetTickCount();
+
+ if( ( xEndTime - xStartTime ) > xMaxTime )
+ {
+ /* Wated more than xMaxTime, return. */
+ xReturn = pdFALSE;
+ break;
+ }
+
+ /* Check the link status again. */
+ ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
+
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ /* Link is up - return. */
+ xReturn = pdTRUE;
+ break;
+ }
+
+ /* Link is down - wait in the Blocked state for a short while (to allow
+ other tasks to execute) before checking again. */
+ vTaskDelay( xShortTime );
+ }
+
+ FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
+ xReturn,
+ ethernet_phy_addr,
+ sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+//#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
+
+ void vGMACGenerateChecksum( uint8_t *apBuffer )
+ {
+ ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;
+
+ if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
+ {
+ IPHeader_t *pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader );
+
+ /* Calculate the IP header checksum. */
+ pxIPHeader->usHeaderChecksum = 0x00;
+ pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
+ pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
+
+ /* Calculate the TCP checksum for an outgoing packet. */
+ usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
+ }
+ }
+
+//#endif
+/*-----------------------------------------------------------*/
+
+static uint32_t prvEMACRxPoll( void )
+{
+unsigned char *pucUseBuffer;
+uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
+static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;
+const UBaseType_t xMinDescriptorsToLeave = 2UL;
+const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
+static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
+
+ for( ;; )
+ {
+ /* If pxNextNetworkBufferDescriptor was not left pointing at a valid
+ descriptor then allocate one now. */
+ if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
+ {
+ pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
+ }
+
+ if( pxNextNetworkBufferDescriptor != NULL )
+ {
+ /* Point pucUseBuffer to the buffer pointed to by the descriptor. */
+ pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
+ }
+ else
+ {
+ /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
+ messages will be flushed and ignored. */
+ pucUseBuffer = NULL;
+ }
+
+ /* Read the next packet from the hardware into pucUseBuffer. */
+ ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );
+
+ if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
+ {
+ /* No data from the hardware. */
+ break;
+ }
+
+ if( pxNextNetworkBufferDescriptor == NULL )
+ {
+ /* Data was read from the hardware, but no descriptor was available
+ for it, so it will be dropped. */
+ iptraceETHERNET_RX_EVENT_LOST();
+ continue;
+ }
+
+ iptraceNETWORK_INTERFACE_RECEIVE();
+ pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
+ xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
+
+ /* Send the descriptor to the IP task for processing. */
+ if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
+ {
+ /* The buffer could not be sent to the stack so must be released
+ again. */
+ vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
+ iptraceETHERNET_RX_EVENT_LOST();
+ FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
+ }
+
+ /* Now the buffer has either been passed to the IP-task,
+ or it has been released in the code above. */
+ pxNextNetworkBufferDescriptor = NULL;
+ ulReturnValue++;
+ }
+
+ return ulReturnValue;
+}
+/*-----------------------------------------------------------*/
+
+void vCheckBuffersAndQueue( void )
+{
+static UBaseType_t uxLastMinBufferCount = 0;
+#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+ static UBaseType_t uxLastMinQueueSpace;
+#endif
+static UBaseType_t uxCurrentCount;
+
+ #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+ {
+ uxCurrentCount = uxGetMinimumIPQueueSpace();
+ if( uxLastMinQueueSpace != uxCurrentCount )
+ {
+ /* The logging produced below may be helpful
+ while tuning +TCP: see how many buffers are in use. */
+ uxLastMinQueueSpace = uxCurrentCount;
+ FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
+ }
+ }
+ #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
+ uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
+ if( uxLastMinBufferCount != uxCurrentCount )
+ {
+ /* The logging produced below may be helpful
+ while tuning +TCP: see how many buffers are in use. */
+ uxLastMinBufferCount = uxCurrentCount;
+ FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
+ uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
+ }
+
+}
+
+static void prvEMACHandlerTask( void *pvParameters )
+{
+TimeOut_t xPhyTime;
+TickType_t xPhyRemTime;
+UBaseType_t uxCount;
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ NetworkBufferDescriptor_t *pxBuffer;
+#endif
+uint8_t *pucBuffer;
+BaseType_t xResult = 0;
+uint32_t xStatus;
+const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
+
+ /* Remove compiler warnings about unused parameters. */
+ ( void ) pvParameters;
+
+ configASSERT( xEMACTaskHandle );
+
+ vTaskSetTimeOutState( &xPhyTime );
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+
+ for( ;; )
+ {
+ vCheckBuffersAndQueue();
+
+ if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
+ {
+ /* No events to process now, wait for the next. */
+ ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
+ }
+
+ if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
+ {
+ ulISREvents &= ~EMAC_IF_RX_EVENT;
+
+ /* Wait for the EMAC interrupt to indicate that another packet has been
+ received. */
+ xResult = prvEMACRxPoll();
+ }
+
+ if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
+ {
+ /* Future extension: code to release TX buffers if zero-copy is used. */
+ ulISREvents &= ~EMAC_IF_TX_EVENT;
+ while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
+ {
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
+ if( pxBuffer != NULL )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxBuffer );
+ tx_release_count[ 0 ]++;
+ }
+ else
+ {
+ tx_release_count[ 1 ]++;
+ }
+ }
+ #else
+ {
+ tx_release_count[ 0 ]++;
+ }
+ #endif
+ uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
+ if( uxCount < GMAC_TX_BUFFERS )
+ {
+ /* Tell the counting semaphore that one more TX descriptor is available. */
+ xSemaphoreGive( xTXDescriptorSemaphore );
+ }
+ }
+ }
+
+ if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
+ {
+ /* Future extension: logging about errors that occurred. */
+ ulISREvents &= ~EMAC_IF_ERR_EVENT;
+ }
+
+ if( xResult > 0 )
+ {
+ /* A packet was received. No need to check for the PHY status now,
+ but set a timer to check it later on. */
+ vTaskSetTimeOutState( &xPhyTime );
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+ xResult = 0;
+ }
+ else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
+ {
+ /* Check the link status again. */
+ xStatus = ulReadMDIO( PHY_REG_01_BMSR );
+
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
+ {
+ ulPHYLinkStatus = xStatus;
+ FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
+ }
+
+ vTaskSetTimeOutState( &xPhyTime );
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+ }
+ else
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/component/gmac.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/component/gmac.h
new file mode 100644
index 000000000..6eb069f55
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/component/gmac.h
@@ -0,0 +1,746 @@
+/**
+ * \file
+ *
+ * Copyright (c) 2012 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#ifndef _SAM4E_GMAC_COMPONENT_
+#define _SAM4E_GMAC_COMPONENT_
+
+/* ============================================================================= */
+/** SOFTWARE API DEFINITION FOR Gigabit Ethernet MAC */
+/* ============================================================================= */
+/** \addtogroup SAM4E_GMAC Gigabit Ethernet MAC */
+/*@{*/
+
+#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
+/** \brief GmacSa hardware registers */
+typedef struct {
+ RwReg GMAC_SAB; /**< \brief (GmacSa Offset: 0x0) Specific Address 1 Bottom [31:0] Register */
+ RwReg GMAC_SAT; /**< \brief (GmacSa Offset: 0x4) Specific Address 1 Top [47:32] Register */
+} GmacSa;
+/** \brief Gmac hardware registers */
+#define GMACSA_NUMBER 4
+typedef struct {
+ RwReg GMAC_NCR; /**< \brief (Gmac Offset: 0x000) Network Control Register */
+ RwReg GMAC_NCFGR; /**< \brief (Gmac Offset: 0x004) Network Configuration Register */
+ RoReg GMAC_NSR; /**< \brief (Gmac Offset: 0x008) Network Status Register */
+ RwReg GMAC_UR; /**< \brief (Gmac Offset: 0x00C) User Register */
+ RwReg GMAC_DCFGR; /**< \brief (Gmac Offset: 0x010) DMA Configuration Register */
+ RwReg GMAC_TSR; /**< \brief (Gmac Offset: 0x014) Transmit Status Register */
+ RwReg GMAC_RBQB; /**< \brief (Gmac Offset: 0x018) Receive Buffer Queue Base Address */
+ RwReg GMAC_TBQB; /**< \brief (Gmac Offset: 0x01C) Transmit Buffer Queue Base Address */
+ RwReg GMAC_RSR; /**< \brief (Gmac Offset: 0x020) Receive Status Register */
+ RoReg GMAC_ISR; /**< \brief (Gmac Offset: 0x024) Interrupt Status Register */
+ WoReg GMAC_IER; /**< \brief (Gmac Offset: 0x028) Interrupt Enable Register */
+ WoReg GMAC_IDR; /**< \brief (Gmac Offset: 0x02C) Interrupt Disable Register */
+ RoReg GMAC_IMR; /**< \brief (Gmac Offset: 0x030) Interrupt Mask Register */
+ RwReg GMAC_MAN; /**< \brief (Gmac Offset: 0x034) PHY Maintenance Register */
+ RoReg GMAC_RPQ; /**< \brief (Gmac Offset: 0x038) Received Pause Quantum Register */
+ RwReg GMAC_TPQ; /**< \brief (Gmac Offset: 0x03C) Transmit Pause Quantum Register */
+ RwReg GMAC_TPSF; /**< \brief (Gmac Offset: 0x040) TX Partial Store and Forward Register */
+ RwReg GMAC_RPSF; /**< \brief (Gmac Offset: 0x044) RX Partial Store and Forward Register */
+ RoReg Reserved1[14];
+ RwReg GMAC_HRB; /**< \brief (Gmac Offset: 0x080) Hash Register Bottom [31:0] */
+ RwReg GMAC_HRT; /**< \brief (Gmac Offset: 0x084) Hash Register Top [63:32] */
+ GmacSa GMAC_SA[GMACSA_NUMBER]; /**< \brief (Gmac Offset: 0x088) 1 .. 4 */
+ RwReg GMAC_TIDM[4]; /**< \brief (Gmac Offset: 0x0A8) Type ID Match 1 Register */
+ RwReg GMAC_WOL; /**< \brief (Gmac Offset: 0x0B8) Wake on LAN Register */
+ RwReg GMAC_IPGS; /**< \brief (Gmac Offset: 0x0BC) IPG Stretch Register */
+ RwReg GMAC_SVLAN; /**< \brief (Gmac Offset: 0x0C0) Stacked VLAN Register */
+ RwReg GMAC_TPFCP; /**< \brief (Gmac Offset: 0x0C4) Transmit PFC Pause Register */
+ RwReg GMAC_SAMB1; /**< \brief (Gmac Offset: 0x0C8) Specific Address 1 Mask Bottom [31:0] Register */
+ RwReg GMAC_SAMT1; /**< \brief (Gmac Offset: 0x0CC) Specific Address 1 Mask Top [47:32] Register */
+ RoReg Reserved2[12];
+ RoReg GMAC_OTLO; /**< \brief (Gmac Offset: 0x100) Octets Transmitted [31:0] Register */
+ RoReg GMAC_OTHI; /**< \brief (Gmac Offset: 0x104) Octets Transmitted [47:32] Register */
+ RoReg GMAC_FT; /**< \brief (Gmac Offset: 0x108) Frames Transmitted Register */
+ RoReg GMAC_BCFT; /**< \brief (Gmac Offset: 0x10C) Broadcast Frames Transmitted Register */
+ RoReg GMAC_MFT; /**< \brief (Gmac Offset: 0x110) Multicast Frames Transmitted Register */
+ RoReg GMAC_PFT; /**< \brief (Gmac Offset: 0x114) Pause Frames Transmitted Register */
+ RoReg GMAC_BFT64; /**< \brief (Gmac Offset: 0x118) 64 Byte Frames Transmitted Register */
+ RoReg GMAC_TBFT127; /**< \brief (Gmac Offset: 0x11C) 65 to 127 Byte Frames Transmitted Register */
+ RoReg GMAC_TBFT255; /**< \brief (Gmac Offset: 0x120) 128 to 255 Byte Frames Transmitted Register */
+ RoReg GMAC_TBFT511; /**< \brief (Gmac Offset: 0x124) 256 to 511 Byte Frames Transmitted Register */
+ RoReg GMAC_TBFT1023; /**< \brief (Gmac Offset: 0x128) 512 to 1023 Byte Frames Transmitted Register */
+ RoReg GMAC_TBFT1518; /**< \brief (Gmac Offset: 0x12C) 1024 to 1518 Byte Frames Transmitted Register */
+ RoReg GMAC_GTBFT1518; /**< \brief (Gmac Offset: 0x130) Greater Than 1518 Byte Frames Transmitted Register */
+ RoReg GMAC_TUR; /**< \brief (Gmac Offset: 0x134) Transmit Under Runs Register */
+ RoReg GMAC_SCF; /**< \brief (Gmac Offset: 0x138) Single Collision Frames Register */
+ RoReg GMAC_MCF; /**< \brief (Gmac Offset: 0x13C) Multiple Collision Frames Register */
+ RoReg GMAC_EC; /**< \brief (Gmac Offset: 0x140) Excessive Collisions Register */
+ RoReg GMAC_LC; /**< \brief (Gmac Offset: 0x144) Late Collisions Register */
+ RoReg GMAC_DTF; /**< \brief (Gmac Offset: 0x148) Deferred Transmission Frames Register */
+ RoReg GMAC_CSE; /**< \brief (Gmac Offset: 0x14C) Carrier Sense Errors Register */
+ RoReg GMAC_ORLO; /**< \brief (Gmac Offset: 0x150) Octets Received [31:0] Received */
+ RoReg GMAC_ORHI; /**< \brief (Gmac Offset: 0x154) Octets Received [47:32] Received */
+ RoReg GMAC_FR; /**< \brief (Gmac Offset: 0x158) Frames Received Register */
+ RoReg GMAC_BCFR; /**< \brief (Gmac Offset: 0x15C) Broadcast Frames Received Register */
+ RoReg GMAC_MFR; /**< \brief (Gmac Offset: 0x160) Multicast Frames Received Register */
+ RoReg GMAC_PFR; /**< \brief (Gmac Offset: 0x164) Pause Frames Received Register */
+ RoReg GMAC_BFR64; /**< \brief (Gmac Offset: 0x168) 64 Byte Frames Received Register */
+ RoReg GMAC_TBFR127; /**< \brief (Gmac Offset: 0x16C) 65 to 127 Byte Frames Received Register */
+ RoReg GMAC_TBFR255; /**< \brief (Gmac Offset: 0x170) 128 to 255 Byte Frames Received Register */
+ RoReg GMAC_TBFR511; /**< \brief (Gmac Offset: 0x174) 256 to 511Byte Frames Received Register */
+ RoReg GMAC_TBFR1023; /**< \brief (Gmac Offset: 0x178) 512 to 1023 Byte Frames Received Register */
+ RoReg GMAC_TBFR1518; /**< \brief (Gmac Offset: 0x17C) 1024 to 1518 Byte Frames Received Register */
+ RoReg GMAC_TMXBFR; /**< \brief (Gmac Offset: 0x180) 1519 to Maximum Byte Frames Received Register */
+ RoReg GMAC_UFR; /**< \brief (Gmac Offset: 0x184) Undersize Frames Received Register */
+ RoReg GMAC_OFR; /**< \brief (Gmac Offset: 0x188) Oversize Frames Received Register */
+ RoReg GMAC_JR; /**< \brief (Gmac Offset: 0x18C) Jabbers Received Register */
+ RoReg GMAC_FCSE; /**< \brief (Gmac Offset: 0x190) Frame Check Sequence Errors Register */
+ RoReg GMAC_LFFE; /**< \brief (Gmac Offset: 0x194) Length Field Frame Errors Register */
+ RoReg GMAC_RSE; /**< \brief (Gmac Offset: 0x198) Receive Symbol Errors Register */
+ RoReg GMAC_AE; /**< \brief (Gmac Offset: 0x19C) Alignment Errors Register */
+ RoReg GMAC_RRE; /**< \brief (Gmac Offset: 0x1A0) Receive Resource Errors Register */
+ RoReg GMAC_ROE; /**< \brief (Gmac Offset: 0x1A4) Receive Overrun Register */
+ RoReg GMAC_IHCE; /**< \brief (Gmac Offset: 0x1A8) IP Header Checksum Errors Register */
+ RoReg GMAC_TCE; /**< \brief (Gmac Offset: 0x1AC) TCP Checksum Errors Register */
+ RoReg GMAC_UCE; /**< \brief (Gmac Offset: 0x1B0) UDP Checksum Errors Register */
+ RoReg Reserved3[5];
+ RwReg GMAC_TSSS; /**< \brief (Gmac Offset: 0x1C8) 1588 Timer Sync Strobe Seconds Register */
+ RwReg GMAC_TSSN; /**< \brief (Gmac Offset: 0x1CC) 1588 Timer Sync Strobe Nanoseconds Register */
+ RwReg GMAC_TS; /**< \brief (Gmac Offset: 0x1D0) 1588 Timer Seconds Register */
+ RwReg GMAC_TN; /**< \brief (Gmac Offset: 0x1D4) 1588 Timer Nanoseconds Register */
+ WoReg GMAC_TA; /**< \brief (Gmac Offset: 0x1D8) 1588 Timer Adjust Register */
+ RwReg GMAC_TI; /**< \brief (Gmac Offset: 0x1DC) 1588 Timer Increment Register */
+ RoReg GMAC_EFTS; /**< \brief (Gmac Offset: 0x1E0) PTP Event Frame Transmitted Seconds */
+ RoReg GMAC_EFTN; /**< \brief (Gmac Offset: 0x1E4) PTP Event Frame Transmitted Nanoseconds */
+ RoReg GMAC_EFRS; /**< \brief (Gmac Offset: 0x1E8) PTP Event Frame Received Seconds */
+ RoReg GMAC_EFRN; /**< \brief (Gmac Offset: 0x1EC) PTP Event Frame Received Nanoseconds */
+ RoReg GMAC_PEFTS; /**< \brief (Gmac Offset: 0x1F0) PTP Peer Event Frame Transmitted Seconds */
+ RoReg GMAC_PEFTN; /**< \brief (Gmac Offset: 0x1F4) PTP Peer Event Frame Transmitted Nanoseconds */
+ RoReg GMAC_PEFRS; /**< \brief (Gmac Offset: 0x1F8) PTP Peer Event Frame Received Seconds */
+ RoReg GMAC_PEFRN; /**< \brief (Gmac Offset: 0x1FC) PTP Peer Event Frame Received Nanoseconds */
+ RoReg Reserved4[128];
+ RoReg GMAC_ISRPQ[7]; /**< \brief (Gmac Offset: 0x400) Interrupt Status Register Priority Queue */
+ RoReg Reserved5[9];
+ RwReg GMAC_TBQBAPQ[7]; /**< \brief (Gmac Offset: 0x440) Transmit Buffer Queue Base Address Priority Queue */
+ RoReg Reserved6[9];
+ RwReg GMAC_RBQBAPQ[7]; /**< \brief (Gmac Offset: 0x480) Receive Buffer Queue Base Address Priority Queue */
+ RoReg Reserved7[1];
+ RwReg GMAC_RBSRPQ[7]; /**< \brief (Gmac Offset: 0x4A0) Receive Buffer Size Register Priority Queue */
+ RoReg Reserved8[17];
+ RwReg GMAC_ST1RPQ[16]; /**< \brief (Gmac Offset: 0x500) Screening Type1 Register Priority Queue */
+ RwReg GMAC_ST2RPQ[16]; /**< \brief (Gmac Offset: 0x540) Screening Type2 Register Priority Queue */
+ RoReg Reserved9[32];
+ WoReg GMAC_IERPQ[7]; /**< \brief (Gmac Offset: 0x600) Interrupt Enable Register Priority Queue */
+ RoReg Reserved10[1];
+ WoReg GMAC_IDRPQ[7]; /**< \brief (Gmac Offset: 0x620) Interrupt Disable Register Priority Queue */
+ RoReg Reserved11[1];
+ RwReg GMAC_IMRPQ[7]; /**< \brief (Gmac Offset: 0x640) Interrupt Mask Register Priority Queue */
+} Gmac;
+#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
+/* -------- GMAC_NCR : (GMAC Offset: 0x000) Network Control Register -------- */
+#define GMAC_NCR_LB (0x1u << 0) /**< \brief (GMAC_NCR) Loop Back */
+#define GMAC_NCR_LBL (0x1u << 1) /**< \brief (GMAC_NCR) Loop Back Local */
+#define GMAC_NCR_RXEN (0x1u << 2) /**< \brief (GMAC_NCR) Receive Enable */
+#define GMAC_NCR_TXEN (0x1u << 3) /**< \brief (GMAC_NCR) Transmit Enable */
+#define GMAC_NCR_MPE (0x1u << 4) /**< \brief (GMAC_NCR) Management Port Enable */
+#define GMAC_NCR_CLRSTAT (0x1u << 5) /**< \brief (GMAC_NCR) Clear Statistics Registers */
+#define GMAC_NCR_INCSTAT (0x1u << 6) /**< \brief (GMAC_NCR) Increment Statistics Registers */
+#define GMAC_NCR_WESTAT (0x1u << 7) /**< \brief (GMAC_NCR) Write Enable for Statistics Registers */
+#define GMAC_NCR_BP (0x1u << 8) /**< \brief (GMAC_NCR) Back pressure */
+#define GMAC_NCR_TSTART (0x1u << 9) /**< \brief (GMAC_NCR) Start Transmission */
+#define GMAC_NCR_THALT (0x1u << 10) /**< \brief (GMAC_NCR) Transmit Halt */
+#define GMAC_NCR_TXPF (0x1u << 11) /**< \brief (GMAC_NCR) Transmit Pause Frame */
+#define GMAC_NCR_TXZQPF (0x1u << 12) /**< \brief (GMAC_NCR) Transmit Zero Quantum Pause Frame */
+#define GMAC_NCR_RDS (0x1u << 14) /**< \brief (GMAC_NCR) Read Snapshot */
+#define GMAC_NCR_SRTSM (0x1u << 15) /**< \brief (GMAC_NCR) Store Receive Time Stamp to Memory */
+#define GMAC_NCR_ENPBPR (0x1u << 16) /**< \brief (GMAC_NCR) Enable PFC Priority-based Pause Reception */
+#define GMAC_NCR_TXPBPF (0x1u << 17) /**< \brief (GMAC_NCR) Transmit PFC Priority-based Pause Frame */
+#define GMAC_NCR_FNP (0x1u << 18) /**< \brief (GMAC_NCR) Flush Next Packet */
+/* -------- GMAC_NCFGR : (GMAC Offset: 0x004) Network Configuration Register -------- */
+#define GMAC_NCFGR_SPD (0x1u << 0) /**< \brief (GMAC_NCFGR) Speed */
+#define GMAC_NCFGR_FD (0x1u << 1) /**< \brief (GMAC_NCFGR) Full Duplex */
+#define GMAC_NCFGR_DNVLAN (0x1u << 2) /**< \brief (GMAC_NCFGR) Discard Non-VLAN FRAMES */
+#define GMAC_NCFGR_JFRAME (0x1u << 3) /**< \brief (GMAC_NCFGR) Jumbo Frame Size */
+#define GMAC_NCFGR_CAF (0x1u << 4) /**< \brief (GMAC_NCFGR) Copy All Frames */
+#define GMAC_NCFGR_NBC (0x1u << 5) /**< \brief (GMAC_NCFGR) No Broadcast */
+#define GMAC_NCFGR_MTIHEN (0x1u << 6) /**< \brief (GMAC_NCFGR) Multicast Hash Enable */
+#define GMAC_NCFGR_UNIHEN (0x1u << 7) /**< \brief (GMAC_NCFGR) Unicast Hash Enable */
+#define GMAC_NCFGR_MAXFS (0x1u << 8) /**< \brief (GMAC_NCFGR) 1536 Maximum Frame Size */
+#define GMAC_NCFGR_GBE (0x1u << 10) /**< \brief (GMAC_NCFGR) Gigabit Mode Enable */
+#define GMAC_NCFGR_PIS (0x1u << 11) /**< \brief (GMAC_NCFGR) Physical Interface Select */
+#define GMAC_NCFGR_RTY (0x1u << 12) /**< \brief (GMAC_NCFGR) Retry Test */
+#define GMAC_NCFGR_PEN (0x1u << 13) /**< \brief (GMAC_NCFGR) Pause Enable */
+#define GMAC_NCFGR_RXBUFO_Pos 14
+#define GMAC_NCFGR_RXBUFO_Msk (0x3u << GMAC_NCFGR_RXBUFO_Pos) /**< \brief (GMAC_NCFGR) Receive Buffer Offset */
+#define GMAC_NCFGR_RXBUFO(value) ((GMAC_NCFGR_RXBUFO_Msk & ((value) << GMAC_NCFGR_RXBUFO_Pos)))
+#define GMAC_NCFGR_LFERD (0x1u << 16) /**< \brief (GMAC_NCFGR) Length Field Error Frame Discard */
+#define GMAC_NCFGR_RFCS (0x1u << 17) /**< \brief (GMAC_NCFGR) Remove FCS */
+#define GMAC_NCFGR_CLK_Pos 18
+#define GMAC_NCFGR_CLK_Msk (0x7u << GMAC_NCFGR_CLK_Pos) /**< \brief (GMAC_NCFGR) MDC CLock Division */
+#define GMAC_NCFGR_CLK_MCK_8 (0x0u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 8 (MCK up to 20 MHz) */
+#define GMAC_NCFGR_CLK_MCK_16 (0x1u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 16 (MCK up to 40 MHz) */
+#define GMAC_NCFGR_CLK_MCK_32 (0x2u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 32 (MCK up to 80 MHz) */
+#define GMAC_NCFGR_CLK_MCK_48 (0x3u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 48 (MCK up to 120MHz) */
+#define GMAC_NCFGR_CLK_MCK_64 (0x4u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 64 (MCK up to 160 MHz) */
+#define GMAC_NCFGR_CLK_MCK_96 (0x5u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 96 (MCK up to 240 MHz) */
+#define GMAC_NCFGR_CLK_MCK_128 (0x6u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 128 (MCK up to 320 MHz) */
+#define GMAC_NCFGR_CLK_MCK_224 (0x7u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 224 (MCK up to 540 MHz) */
+#define GMAC_NCFGR_DBW_Pos 21
+#define GMAC_NCFGR_DBW_Msk (0x3u << GMAC_NCFGR_DBW_Pos) /**< \brief (GMAC_NCFGR) Data Bus Width */
+#define GMAC_NCFGR_DBW_DBW32 (0x0u << 21) /**< \brief (GMAC_NCFGR) 32-bit data bus width */
+#define GMAC_NCFGR_DBW_DBW64 (0x1u << 21) /**< \brief (GMAC_NCFGR) 64-bit data bus width */
+#define GMAC_NCFGR_DCPF (0x1u << 23) /**< \brief (GMAC_NCFGR) Disable Copy of Pause Frames */
+#define GMAC_NCFGR_RXCOEN (0x1u << 24) /**< \brief (GMAC_NCFGR) Receive Checksum Offload Enable */
+#define GMAC_NCFGR_EFRHD (0x1u << 25) /**< \brief (GMAC_NCFGR) Enable Frames Received in Half Duplex */
+#define GMAC_NCFGR_IRXFCS (0x1u << 26) /**< \brief (GMAC_NCFGR) Ignore RX FCS */
+#define GMAC_NCFGR_IPGSEN (0x1u << 28) /**< \brief (GMAC_NCFGR) IP Stretch Enable */
+#define GMAC_NCFGR_RXBP (0x1u << 29) /**< \brief (GMAC_NCFGR) Receive Bad Preamble */
+#define GMAC_NCFGR_IRXER (0x1u << 30) /**< \brief (GMAC_NCFGR) Ignore IPG rx_er */
+/* -------- GMAC_NSR : (GMAC Offset: 0x008) Network Status Register -------- */
+#define GMAC_NSR_MDIO (0x1u << 1) /**< \brief (GMAC_NSR) MDIO Input Status */
+#define GMAC_NSR_IDLE (0x1u << 2) /**< \brief (GMAC_NSR) PHY Management Logic Idle */
+/* -------- GMAC_UR : (GMAC Offset: 0x00C) User Register -------- */
+#define GMAC_UR_RGMII (0x1u << 0) /**< \brief (GMAC_UR) RGMII Mode */
+#define GMAC_UR_HDFC (0x1u << 6) /**< \brief (GMAC_UR) Half Duplex Flow Control */
+#define GMAC_UR_BPDG (0x1u << 7) /**< \brief (GMAC_UR) BPDG Bypass Deglitchers */
+/* -------- GMAC_DCFGR : (GMAC Offset: 0x010) DMA Configuration Register -------- */
+#define GMAC_DCFGR_FBLDO_Pos 0
+#define GMAC_DCFGR_FBLDO_Msk (0x1fu << GMAC_DCFGR_FBLDO_Pos) /**< \brief (GMAC_DCFGR) Fixed Burst Length for DMA Data Operations: */
+#define GMAC_DCFGR_FBLDO_SINGLE (0x1u << 0) /**< \brief (GMAC_DCFGR) 00001: Always use SINGLE AHB bursts */
+#define GMAC_DCFGR_FBLDO_INCR4 (0x4u << 0) /**< \brief (GMAC_DCFGR) 001xx: Attempt to use INCR4 AHB bursts (Default) */
+#define GMAC_DCFGR_FBLDO_INCR8 (0x8u << 0) /**< \brief (GMAC_DCFGR) 01xxx: Attempt to use INCR8 AHB bursts */
+#define GMAC_DCFGR_FBLDO_INCR16 (0x10u << 0) /**< \brief (GMAC_DCFGR) 1xxxx: Attempt to use INCR16 AHB bursts */
+#define GMAC_DCFGR_ESMA (0x1u << 6) /**< \brief (GMAC_DCFGR) Endian Swap Mode Enable for Management Descriptor Accesses */
+#define GMAC_DCFGR_ESPA (0x1u << 7) /**< \brief (GMAC_DCFGR) Endian Swap Mode Enable for Packet Data Accesses */
+#define GMAC_DCFGR_RXBMS_Pos 8
+#define GMAC_DCFGR_RXBMS_Msk (0x3u << GMAC_DCFGR_RXBMS_Pos) /**< \brief (GMAC_DCFGR) Receiver Packet Buffer Memory Size Select */
+#define GMAC_DCFGR_RXBMS_EIGHTH (0x0u << 8) /**< \brief (GMAC_DCFGR) 1 Kbyte Memory Size */
+#define GMAC_DCFGR_RXBMS_QUARTER (0x1u << 8) /**< \brief (GMAC_DCFGR) 2 Kbytes Memory Size */
+#define GMAC_DCFGR_RXBMS_HALF (0x2u << 8) /**< \brief (GMAC_DCFGR) 4 Kbytes Memory Size */
+#define GMAC_DCFGR_RXBMS_FULL (0x3u << 8) /**< \brief (GMAC_DCFGR) 8 Kbytes Memory Size */
+#define GMAC_DCFGR_TXPBMS (0x1u << 10) /**< \brief (GMAC_DCFGR) Transmitter Packet Buffer Memory Size Select */
+#define GMAC_DCFGR_TXCOEN (0x1u << 11) /**< \brief (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable */
+#define GMAC_DCFGR_DRBS_Pos 16
+#define GMAC_DCFGR_DRBS_Msk (0xffu << GMAC_DCFGR_DRBS_Pos) /**< \brief (GMAC_DCFGR) DMA Receive Buffer Size */
+#define GMAC_DCFGR_DRBS(value) ((GMAC_DCFGR_DRBS_Msk & ((value) << GMAC_DCFGR_DRBS_Pos)))
+#define GMAC_DCFGR_DDRP (0x1u << 24) /**< \brief (GMAC_DCFGR) DMA Discard Receive Packets */
+/* -------- GMAC_TSR : (GMAC Offset: 0x014) Transmit Status Register -------- */
+#define GMAC_TSR_UBR (0x1u << 0) /**< \brief (GMAC_TSR) Used Bit Read */
+#define GMAC_TSR_COL (0x1u << 1) /**< \brief (GMAC_TSR) Collision Occurred */
+#define GMAC_TSR_RLE (0x1u << 2) /**< \brief (GMAC_TSR) Retry Limit Exceeded */
+#define GMAC_TSR_TXGO (0x1u << 3) /**< \brief (GMAC_TSR) Transmit Go */
+#define GMAC_TSR_TFC (0x1u << 4) /**< \brief (GMAC_TSR) Transmit Frame Corruption due to AHB error */
+#define GMAC_TSR_TXCOMP (0x1u << 5) /**< \brief (GMAC_TSR) Transmit Complete */
+#define GMAC_TSR_UND (0x1u << 6) /**< \brief (GMAC_TSR) Transmit Under Run */
+#define GMAC_TSR_LCO (0x1u << 7) /**< \brief (GMAC_TSR) Late Collision Occurred */
+#define GMAC_TSR_HRESP (0x1u << 8) /**< \brief (GMAC_TSR) HRESP Not OK */
+/* -------- GMAC_RBQB : (GMAC Offset: 0x018) Receive Buffer Queue Base Address -------- */
+#define GMAC_RBQB_ADDR_Pos 2
+#define GMAC_RBQB_ADDR_Msk (0x3fffffffu << GMAC_RBQB_ADDR_Pos) /**< \brief (GMAC_RBQB) Receive buffer queue base address */
+#define GMAC_RBQB_ADDR(value) ((GMAC_RBQB_ADDR_Msk & ((value) << GMAC_RBQB_ADDR_Pos)))
+/* -------- GMAC_TBQB : (GMAC Offset: 0x01C) Transmit Buffer Queue Base Address -------- */
+#define GMAC_TBQB_ADDR_Pos 2
+#define GMAC_TBQB_ADDR_Msk (0x3fffffffu << GMAC_TBQB_ADDR_Pos) /**< \brief (GMAC_TBQB) Transmit Buffer Queue Base Address */
+#define GMAC_TBQB_ADDR(value) ((GMAC_TBQB_ADDR_Msk & ((value) << GMAC_TBQB_ADDR_Pos)))
+/* -------- GMAC_RSR : (GMAC Offset: 0x020) Receive Status Register -------- */
+#define GMAC_RSR_BNA (0x1u << 0) /**< \brief (GMAC_RSR) Buffer Not Available */
+#define GMAC_RSR_REC (0x1u << 1) /**< \brief (GMAC_RSR) Frame Received */
+#define GMAC_RSR_RXOVR (0x1u << 2) /**< \brief (GMAC_RSR) Receive Overrun */
+#define GMAC_RSR_HNO (0x1u << 3) /**< \brief (GMAC_RSR) HRESP Not OK */
+/* -------- GMAC_ISR : (GMAC Offset: 0x024) Interrupt Status Register -------- */
+#define GMAC_ISR_MFS (0x1u << 0) /**< \brief (GMAC_ISR) Management Frame Sent */
+#define GMAC_ISR_RCOMP (0x1u << 1) /**< \brief (GMAC_ISR) Receive Complete */
+#define GMAC_ISR_RXUBR (0x1u << 2) /**< \brief (GMAC_ISR) RX Used Bit Read */
+#define GMAC_ISR_TXUBR (0x1u << 3) /**< \brief (GMAC_ISR) TX Used Bit Read */
+#define GMAC_ISR_TUR (0x1u << 4) /**< \brief (GMAC_ISR) Transmit Under Run */
+#define GMAC_ISR_RLEX (0x1u << 5) /**< \brief (GMAC_ISR) Retry Limit Exceeded or Late Collision */
+#define GMAC_ISR_TFC (0x1u << 6) /**< \brief (GMAC_ISR) Transmit Frame Corruption due to AHB error */
+#define GMAC_ISR_TCOMP (0x1u << 7) /**< \brief (GMAC_ISR) Transmit Complete */
+#define GMAC_ISR_ROVR (0x1u << 10) /**< \brief (GMAC_ISR) Receive Overrun */
+#define GMAC_ISR_HRESP (0x1u << 11) /**< \brief (GMAC_ISR) HRESP Not OK */
+#define GMAC_ISR_PFNZ (0x1u << 12) /**< \brief (GMAC_ISR) Pause Frame with Non-zero Pause Quantum Received */
+#define GMAC_ISR_PTZ (0x1u << 13) /**< \brief (GMAC_ISR) Pause Time Zero */
+#define GMAC_ISR_PFTR (0x1u << 14) /**< \brief (GMAC_ISR) Pause Frame Transmitted */
+#define GMAC_ISR_EXINT (0x1u << 15) /**< \brief (GMAC_ISR) External Interrupt */
+#define GMAC_ISR_DRQFR (0x1u << 18) /**< \brief (GMAC_ISR) PTP Delay Request Frame Received */
+#define GMAC_ISR_SFR (0x1u << 19) /**< \brief (GMAC_ISR) PTP Sync Frame Received */
+#define GMAC_ISR_DRQFT (0x1u << 20) /**< \brief (GMAC_ISR) PTP Delay Request Frame Transmitted */
+#define GMAC_ISR_SFT (0x1u << 21) /**< \brief (GMAC_ISR) PTP Sync Frame Transmitted */
+#define GMAC_ISR_PDRQFR (0x1u << 22) /**< \brief (GMAC_ISR) PDelay Request Frame Received */
+#define GMAC_ISR_PDRSFR (0x1u << 23) /**< \brief (GMAC_ISR) PDelay Response Frame Received */
+#define GMAC_ISR_PDRQFT (0x1u << 24) /**< \brief (GMAC_ISR) PDelay Request Frame Transmitted */
+#define GMAC_ISR_PDRSFT (0x1u << 25) /**< \brief (GMAC_ISR) PDelay Response Frame Transmitted */
+#define GMAC_ISR_SRI (0x1u << 26) /**< \brief (GMAC_ISR) TSU Seconds Register Increment */
+#define GMAC_ISR_WOL (0x1u << 28) /**< \brief (GMAC_ISR) Wake On LAN */
+/* -------- GMAC_IER : (GMAC Offset: 0x028) Interrupt Enable Register -------- */
+#define GMAC_IER_MFS (0x1u << 0) /**< \brief (GMAC_IER) Management Frame Sent */
+#define GMAC_IER_RCOMP (0x1u << 1) /**< \brief (GMAC_IER) Receive Complete */
+#define GMAC_IER_RXUBR (0x1u << 2) /**< \brief (GMAC_IER) RX Used Bit Read */
+#define GMAC_IER_TXUBR (0x1u << 3) /**< \brief (GMAC_IER) TX Used Bit Read */
+#define GMAC_IER_TUR (0x1u << 4) /**< \brief (GMAC_IER) Transmit Under Run */
+#define GMAC_IER_RLEX (0x1u << 5) /**< \brief (GMAC_IER) Retry Limit Exceeded or Late Collision */
+#define GMAC_IER_TFC (0x1u << 6) /**< \brief (GMAC_IER) Transmit Frame Corruption due to AHB error */
+#define GMAC_IER_TCOMP (0x1u << 7) /**< \brief (GMAC_IER) Transmit Complete */
+#define GMAC_IER_ROVR (0x1u << 10) /**< \brief (GMAC_IER) Receive Overrun */
+#define GMAC_IER_HRESP (0x1u << 11) /**< \brief (GMAC_IER) HRESP Not OK */
+#define GMAC_IER_PFNZ (0x1u << 12) /**< \brief (GMAC_IER) Pause Frame with Non-zero Pause Quantum Received */
+#define GMAC_IER_PTZ (0x1u << 13) /**< \brief (GMAC_IER) Pause Time Zero */
+#define GMAC_IER_PFTR (0x1u << 14) /**< \brief (GMAC_IER) Pause Frame Transmitted */
+#define GMAC_IER_EXINT (0x1u << 15) /**< \brief (GMAC_IER) External Interrupt */
+#define GMAC_IER_DRQFR (0x1u << 18) /**< \brief (GMAC_IER) PTP Delay Request Frame Received */
+#define GMAC_IER_SFR (0x1u << 19) /**< \brief (GMAC_IER) PTP Sync Frame Received */
+#define GMAC_IER_DRQFT (0x1u << 20) /**< \brief (GMAC_IER) PTP Delay Request Frame Transmitted */
+#define GMAC_IER_SFT (0x1u << 21) /**< \brief (GMAC_IER) PTP Sync Frame Transmitted */
+#define GMAC_IER_PDRQFR (0x1u << 22) /**< \brief (GMAC_IER) PDelay Request Frame Received */
+#define GMAC_IER_PDRSFR (0x1u << 23) /**< \brief (GMAC_IER) PDelay Response Frame Received */
+#define GMAC_IER_PDRQFT (0x1u << 24) /**< \brief (GMAC_IER) PDelay Request Frame Transmitted */
+#define GMAC_IER_PDRSFT (0x1u << 25) /**< \brief (GMAC_IER) PDelay Response Frame Transmitted */
+#define GMAC_IER_SRI (0x1u << 26) /**< \brief (GMAC_IER) TSU Seconds Register Increment */
+#define GMAC_IER_WOL (0x1u << 28) /**< \brief (GMAC_IER) Wake On LAN */
+/* -------- GMAC_IDR : (GMAC Offset: 0x02C) Interrupt Disable Register -------- */
+#define GMAC_IDR_MFS (0x1u << 0) /**< \brief (GMAC_IDR) Management Frame Sent */
+#define GMAC_IDR_RCOMP (0x1u << 1) /**< \brief (GMAC_IDR) Receive Complete */
+#define GMAC_IDR_RXUBR (0x1u << 2) /**< \brief (GMAC_IDR) RX Used Bit Read */
+#define GMAC_IDR_TXUBR (0x1u << 3) /**< \brief (GMAC_IDR) TX Used Bit Read */
+#define GMAC_IDR_TUR (0x1u << 4) /**< \brief (GMAC_IDR) Transmit Under Run */
+#define GMAC_IDR_RLEX (0x1u << 5) /**< \brief (GMAC_IDR) Retry Limit Exceeded or Late Collision */
+#define GMAC_IDR_TFC (0x1u << 6) /**< \brief (GMAC_IDR) Transmit Frame Corruption due to AHB error */
+#define GMAC_IDR_TCOMP (0x1u << 7) /**< \brief (GMAC_IDR) Transmit Complete */
+#define GMAC_IDR_ROVR (0x1u << 10) /**< \brief (GMAC_IDR) Receive Overrun */
+#define GMAC_IDR_HRESP (0x1u << 11) /**< \brief (GMAC_IDR) HRESP Not OK */
+#define GMAC_IDR_PFNZ (0x1u << 12) /**< \brief (GMAC_IDR) Pause Frame with Non-zero Pause Quantum Received */
+#define GMAC_IDR_PTZ (0x1u << 13) /**< \brief (GMAC_IDR) Pause Time Zero */
+#define GMAC_IDR_PFTR (0x1u << 14) /**< \brief (GMAC_IDR) Pause Frame Transmitted */
+#define GMAC_IDR_EXINT (0x1u << 15) /**< \brief (GMAC_IDR) External Interrupt */
+#define GMAC_IDR_DRQFR (0x1u << 18) /**< \brief (GMAC_IDR) PTP Delay Request Frame Received */
+#define GMAC_IDR_SFR (0x1u << 19) /**< \brief (GMAC_IDR) PTP Sync Frame Received */
+#define GMAC_IDR_DRQFT (0x1u << 20) /**< \brief (GMAC_IDR) PTP Delay Request Frame Transmitted */
+#define GMAC_IDR_SFT (0x1u << 21) /**< \brief (GMAC_IDR) PTP Sync Frame Transmitted */
+#define GMAC_IDR_PDRQFR (0x1u << 22) /**< \brief (GMAC_IDR) PDelay Request Frame Received */
+#define GMAC_IDR_PDRSFR (0x1u << 23) /**< \brief (GMAC_IDR) PDelay Response Frame Received */
+#define GMAC_IDR_PDRQFT (0x1u << 24) /**< \brief (GMAC_IDR) PDelay Request Frame Transmitted */
+#define GMAC_IDR_PDRSFT (0x1u << 25) /**< \brief (GMAC_IDR) PDelay Response Frame Transmitted */
+#define GMAC_IDR_SRI (0x1u << 26) /**< \brief (GMAC_IDR) TSU Seconds Register Increment */
+#define GMAC_IDR_WOL (0x1u << 28) /**< \brief (GMAC_IDR) Wake On LAN */
+/* -------- GMAC_IMR : (GMAC Offset: 0x030) Interrupt Mask Register -------- */
+#define GMAC_IMR_MFS (0x1u << 0) /**< \brief (GMAC_IMR) Management Frame Sent */
+#define GMAC_IMR_RCOMP (0x1u << 1) /**< \brief (GMAC_IMR) Receive Complete */
+#define GMAC_IMR_RXUBR (0x1u << 2) /**< \brief (GMAC_IMR) RX Used Bit Read */
+#define GMAC_IMR_TXUBR (0x1u << 3) /**< \brief (GMAC_IMR) TX Used Bit Read */
+#define GMAC_IMR_TUR (0x1u << 4) /**< \brief (GMAC_IMR) Transmit Under Run */
+#define GMAC_IMR_RLEX (0x1u << 5) /**< \brief (GMAC_IMR) Retry Limit Exceeded or Late Collision */
+#define GMAC_IMR_TFC (0x1u << 6) /**< \brief (GMAC_IMR) Transmit Frame Corruption due to AHB error */
+#define GMAC_IMR_TCOMP (0x1u << 7) /**< \brief (GMAC_IMR) Transmit Complete */
+#define GMAC_IMR_ROVR (0x1u << 10) /**< \brief (GMAC_IMR) Receive Overrun */
+#define GMAC_IMR_HRESP (0x1u << 11) /**< \brief (GMAC_IMR) HRESP Not OK */
+#define GMAC_IMR_PFNZ (0x1u << 12) /**< \brief (GMAC_IMR) Pause Frame with Non-zero Pause Quantum Received */
+#define GMAC_IMR_PTZ (0x1u << 13) /**< \brief (GMAC_IMR) Pause Time Zero */
+#define GMAC_IMR_PFTR (0x1u << 14) /**< \brief (GMAC_IMR) Pause Frame Transmitted */
+#define GMAC_IMR_EXINT (0x1u << 15) /**< \brief (GMAC_IMR) External Interrupt */
+#define GMAC_IMR_DRQFR (0x1u << 18) /**< \brief (GMAC_IMR) PTP Delay Request Frame Received */
+#define GMAC_IMR_SFR (0x1u << 19) /**< \brief (GMAC_IMR) PTP Sync Frame Received */
+#define GMAC_IMR_DRQFT (0x1u << 20) /**< \brief (GMAC_IMR) PTP Delay Request Frame Transmitted */
+#define GMAC_IMR_SFT (0x1u << 21) /**< \brief (GMAC_IMR) PTP Sync Frame Transmitted */
+#define GMAC_IMR_PDRQFR (0x1u << 22) /**< \brief (GMAC_IMR) PDelay Request Frame Received */
+#define GMAC_IMR_PDRSFR (0x1u << 23) /**< \brief (GMAC_IMR) PDelay Response Frame Received */
+#define GMAC_IMR_PDRQFT (0x1u << 24) /**< \brief (GMAC_IMR) PDelay Request Frame Transmitted */
+#define GMAC_IMR_PDRSFT (0x1u << 25) /**< \brief (GMAC_IMR) PDelay Response Frame Transmitted */
+/* -------- GMAC_MAN : (GMAC Offset: 0x034) PHY Maintenance Register -------- */
+#define GMAC_MAN_DATA_Pos 0
+#define GMAC_MAN_DATA_Msk (0xffffu << GMAC_MAN_DATA_Pos) /**< \brief (GMAC_MAN) PHY Data */
+#define GMAC_MAN_DATA(value) ((GMAC_MAN_DATA_Msk & ((value) << GMAC_MAN_DATA_Pos)))
+#define GMAC_MAN_WTN_Pos 16
+#define GMAC_MAN_WTN_Msk (0x3u << GMAC_MAN_WTN_Pos) /**< \brief (GMAC_MAN) Write Ten */
+#define GMAC_MAN_WTN(value) ((GMAC_MAN_WTN_Msk & ((value) << GMAC_MAN_WTN_Pos)))
+#define GMAC_MAN_REGA_Pos 18
+#define GMAC_MAN_REGA_Msk (0x1fu << GMAC_MAN_REGA_Pos) /**< \brief (GMAC_MAN) Register Address */
+#define GMAC_MAN_REGA(value) ((GMAC_MAN_REGA_Msk & ((value) << GMAC_MAN_REGA_Pos)))
+#define GMAC_MAN_PHYA_Pos 23
+#define GMAC_MAN_PHYA_Msk (0x1fu << GMAC_MAN_PHYA_Pos) /**< \brief (GMAC_MAN) PHY Address */
+#define GMAC_MAN_PHYA(value) ((GMAC_MAN_PHYA_Msk & ((value) << GMAC_MAN_PHYA_Pos)))
+#define GMAC_MAN_OP_Pos 28
+#define GMAC_MAN_OP_Msk (0x3u << GMAC_MAN_OP_Pos) /**< \brief (GMAC_MAN) Operation */
+#define GMAC_MAN_OP(value) ((GMAC_MAN_OP_Msk & ((value) << GMAC_MAN_OP_Pos)))
+#define GMAC_MAN_CLTTO (0x1u << 30) /**< \brief (GMAC_MAN) Clause 22 Operation */
+#define GMAC_MAN_WZO (0x1u << 31) /**< \brief (GMAC_MAN) Write ZERO */
+/* -------- GMAC_RPQ : (GMAC Offset: 0x038) Received Pause Quantum Register -------- */
+#define GMAC_RPQ_RPQ_Pos 0
+#define GMAC_RPQ_RPQ_Msk (0xffffu << GMAC_RPQ_RPQ_Pos) /**< \brief (GMAC_RPQ) Received Pause Quantum */
+/* -------- GMAC_TPQ : (GMAC Offset: 0x03C) Transmit Pause Quantum Register -------- */
+#define GMAC_TPQ_TPQ_Pos 0
+#define GMAC_TPQ_TPQ_Msk (0xffffu << GMAC_TPQ_TPQ_Pos) /**< \brief (GMAC_TPQ) Transmit Pause Quantum */
+#define GMAC_TPQ_TPQ(value) ((GMAC_TPQ_TPQ_Msk & ((value) << GMAC_TPQ_TPQ_Pos)))
+/* -------- GMAC_TPSF : (GMAC Offset: 0x040) TX Partial Store and Forward Register -------- */
+#define GMAC_TPSF_TPB1ADR_Pos 0
+#define GMAC_TPSF_TPB1ADR_Msk (0xfffu << GMAC_TPSF_TPB1ADR_Pos) /**< \brief (GMAC_TPSF) tx_pbuf_addr-1:0 */
+#define GMAC_TPSF_TPB1ADR(value) ((GMAC_TPSF_TPB1ADR_Msk & ((value) << GMAC_TPSF_TPB1ADR_Pos)))
+#define GMAC_TPSF_ENTXP (0x1u << 31) /**< \brief (GMAC_TPSF) Enable TX Partial Store and Forward Operation */
+/* -------- GMAC_RPSF : (GMAC Offset: 0x044) RX Partial Store and Forward Register -------- */
+#define GMAC_RPSF_RPB1ADR_Pos 0
+#define GMAC_RPSF_RPB1ADR_Msk (0xfffu << GMAC_RPSF_RPB1ADR_Pos) /**< \brief (GMAC_RPSF) rx_pbuf_addr-1:0 */
+#define GMAC_RPSF_RPB1ADR(value) ((GMAC_RPSF_RPB1ADR_Msk & ((value) << GMAC_RPSF_RPB1ADR_Pos)))
+#define GMAC_RPSF_ENRXP (0x1u << 31) /**< \brief (GMAC_RPSF) Enable RX Partial Store and Forward Operation */
+/* -------- GMAC_HRB : (GMAC Offset: 0x080) Hash Register Bottom [31:0] -------- */
+#define GMAC_HRB_ADDR_Pos 0
+#define GMAC_HRB_ADDR_Msk (0xffffffffu << GMAC_HRB_ADDR_Pos) /**< \brief (GMAC_HRB) Hash Address */
+#define GMAC_HRB_ADDR(value) ((GMAC_HRB_ADDR_Msk & ((value) << GMAC_HRB_ADDR_Pos)))
+/* -------- GMAC_HRT : (GMAC Offset: 0x084) Hash Register Top [63:32] -------- */
+#define GMAC_HRT_ADDR_Pos 0
+#define GMAC_HRT_ADDR_Msk (0xffffffffu << GMAC_HRT_ADDR_Pos) /**< \brief (GMAC_HRT) Hash Address */
+#define GMAC_HRT_ADDR(value) ((GMAC_HRT_ADDR_Msk & ((value) << GMAC_HRT_ADDR_Pos)))
+/* -------- GMAC_SAB1 : (GMAC Offset: 0x088) Specific Address 1 Bottom [31:0] Register -------- */
+#define GMAC_SAB1_ADDR_Pos 0
+#define GMAC_SAB1_ADDR_Msk (0xffffffffu << GMAC_SAB1_ADDR_Pos) /**< \brief (GMAC_SAB1) Specific Address 1 */
+#define GMAC_SAB1_ADDR(value) ((GMAC_SAB1_ADDR_Msk & ((value) << GMAC_SAB1_ADDR_Pos)))
+/* -------- GMAC_SAT1 : (GMAC Offset: 0x08C) Specific Address 1 Top [47:32] Register -------- */
+#define GMAC_SAT1_ADDR_Pos 0
+#define GMAC_SAT1_ADDR_Msk (0xffffu << GMAC_SAT1_ADDR_Pos) /**< \brief (GMAC_SAT1) Specific Address 1 */
+#define GMAC_SAT1_ADDR(value) ((GMAC_SAT1_ADDR_Msk & ((value) << GMAC_SAT1_ADDR_Pos)))
+/* -------- GMAC_SAB2 : (GMAC Offset: 0x090) Specific Address 2 Bottom [31:0] Register -------- */
+#define GMAC_SAB2_ADDR_Pos 0
+#define GMAC_SAB2_ADDR_Msk (0xffffffffu << GMAC_SAB2_ADDR_Pos) /**< \brief (GMAC_SAB2) Specific Address 2 */
+#define GMAC_SAB2_ADDR(value) ((GMAC_SAB2_ADDR_Msk & ((value) << GMAC_SAB2_ADDR_Pos)))
+/* -------- GMAC_SAT2 : (GMAC Offset: 0x094) Specific Address 2 Top [47:32] Register -------- */
+#define GMAC_SAT2_ADDR_Pos 0
+#define GMAC_SAT2_ADDR_Msk (0xffffu << GMAC_SAT2_ADDR_Pos) /**< \brief (GMAC_SAT2) Specific Address 2 */
+#define GMAC_SAT2_ADDR(value) ((GMAC_SAT2_ADDR_Msk & ((value) << GMAC_SAT2_ADDR_Pos)))
+/* -------- GMAC_SAB3 : (GMAC Offset: 0x098) Specific Address 3 Bottom [31:0] Register -------- */
+#define GMAC_SAB3_ADDR_Pos 0
+#define GMAC_SAB3_ADDR_Msk (0xffffffffu << GMAC_SAB3_ADDR_Pos) /**< \brief (GMAC_SAB3) Specific Address 3 */
+#define GMAC_SAB3_ADDR(value) ((GMAC_SAB3_ADDR_Msk & ((value) << GMAC_SAB3_ADDR_Pos)))
+/* -------- GMAC_SAT3 : (GMAC Offset: 0x09C) Specific Address 3 Top [47:32] Register -------- */
+#define GMAC_SAT3_ADDR_Pos 0
+#define GMAC_SAT3_ADDR_Msk (0xffffu << GMAC_SAT3_ADDR_Pos) /**< \brief (GMAC_SAT3) Specific Address 3 */
+#define GMAC_SAT3_ADDR(value) ((GMAC_SAT3_ADDR_Msk & ((value) << GMAC_SAT3_ADDR_Pos)))
+/* -------- GMAC_SAB4 : (GMAC Offset: 0x0A0) Specific Address 4 Bottom [31:0] Register -------- */
+#define GMAC_SAB4_ADDR_Pos 0
+#define GMAC_SAB4_ADDR_Msk (0xffffffffu << GMAC_SAB4_ADDR_Pos) /**< \brief (GMAC_SAB4) Specific Address 4 */
+#define GMAC_SAB4_ADDR(value) ((GMAC_SAB4_ADDR_Msk & ((value) << GMAC_SAB4_ADDR_Pos)))
+/* -------- GMAC_SAT4 : (GMAC Offset: 0x0A4) Specific Address 4 Top [47:32] Register -------- */
+#define GMAC_SAT4_ADDR_Pos 0
+#define GMAC_SAT4_ADDR_Msk (0xffffu << GMAC_SAT4_ADDR_Pos) /**< \brief (GMAC_SAT4) Specific Address 4 */
+#define GMAC_SAT4_ADDR(value) ((GMAC_SAT4_ADDR_Msk & ((value) << GMAC_SAT4_ADDR_Pos)))
+/* -------- GMAC_TIDM[4] : (GMAC Offset: 0x0A8) Type ID Match 1 Register -------- */
+#define GMAC_TIDM_TID_Pos 0
+#define GMAC_TIDM_TID_Msk (0xffffu << GMAC_TIDM_TID_Pos) /**< \brief (GMAC_TIDM[4]) Type ID Match 1 */
+#define GMAC_TIDM_TID(value) ((GMAC_TIDM_TID_Msk & ((value) << GMAC_TIDM_TID_Pos)))
+/* -------- GMAC_WOL : (GMAC Offset: 0x0B8) Wake on LAN Register -------- */
+#define GMAC_WOL_IP_Pos 0
+#define GMAC_WOL_IP_Msk (0xffffu << GMAC_WOL_IP_Pos) /**< \brief (GMAC_WOL) ARP Request IP Address */
+#define GMAC_WOL_IP(value) ((GMAC_WOL_IP_Msk & ((value) << GMAC_WOL_IP_Pos)))
+#define GMAC_WOL_MAG (0x1u << 16) /**< \brief (GMAC_WOL) Magic Packet Event Enable */
+#define GMAC_WOL_ARP (0x1u << 17) /**< \brief (GMAC_WOL) ARP Request IP Address */
+#define GMAC_WOL_SA1 (0x1u << 18) /**< \brief (GMAC_WOL) Specific Address Register 1 Event Enable */
+#define GMAC_WOL_MTI (0x1u << 19) /**< \brief (GMAC_WOL) Multicast Hash Event Enable */
+/* -------- GMAC_IPGS : (GMAC Offset: 0x0BC) IPG Stretch Register -------- */
+#define GMAC_IPGS_FL_Pos 0
+#define GMAC_IPGS_FL_Msk (0xffffu << GMAC_IPGS_FL_Pos) /**< \brief (GMAC_IPGS) Frame Length */
+#define GMAC_IPGS_FL(value) ((GMAC_IPGS_FL_Msk & ((value) << GMAC_IPGS_FL_Pos)))
+/* -------- GMAC_SVLAN : (GMAC Offset: 0x0C0) Stacked VLAN Register -------- */
+#define GMAC_SVLAN_VLAN_TYPE_Pos 0
+#define GMAC_SVLAN_VLAN_TYPE_Msk (0xffffu << GMAC_SVLAN_VLAN_TYPE_Pos) /**< \brief (GMAC_SVLAN) User Defined VLAN_TYPE Field */
+#define GMAC_SVLAN_VLAN_TYPE(value) ((GMAC_SVLAN_VLAN_TYPE_Msk & ((value) << GMAC_SVLAN_VLAN_TYPE_Pos)))
+#define GMAC_SVLAN_ESVLAN (0x1u << 31) /**< \brief (GMAC_SVLAN) Enable Stacked VLAN Processing Mode */
+/* -------- GMAC_TPFCP : (GMAC Offset: 0x0C4) Transmit PFC Pause Register -------- */
+#define GMAC_TPFCP_PEV_Pos 0
+#define GMAC_TPFCP_PEV_Msk (0xffu << GMAC_TPFCP_PEV_Pos) /**< \brief (GMAC_TPFCP) Priority Enable Vector */
+#define GMAC_TPFCP_PEV(value) ((GMAC_TPFCP_PEV_Msk & ((value) << GMAC_TPFCP_PEV_Pos)))
+#define GMAC_TPFCP_PQ_Pos 8
+#define GMAC_TPFCP_PQ_Msk (0xffu << GMAC_TPFCP_PQ_Pos) /**< \brief (GMAC_TPFCP) Pause Quantum */
+#define GMAC_TPFCP_PQ(value) ((GMAC_TPFCP_PQ_Msk & ((value) << GMAC_TPFCP_PQ_Pos)))
+/* -------- GMAC_SAMB1 : (GMAC Offset: 0x0C8) Specific Address 1 Mask Bottom [31:0] Register -------- */
+#define GMAC_SAMB1_ADDR_Pos 0
+#define GMAC_SAMB1_ADDR_Msk (0xffffffffu << GMAC_SAMB1_ADDR_Pos) /**< \brief (GMAC_SAMB1) Specific Address 1 Mask */
+#define GMAC_SAMB1_ADDR(value) ((GMAC_SAMB1_ADDR_Msk & ((value) << GMAC_SAMB1_ADDR_Pos)))
+/* -------- GMAC_SAMT1 : (GMAC Offset: 0x0CC) Specific Address 1 Mask Top [47:32] Register -------- */
+#define GMAC_SAMT1_ADDR_Pos 0
+#define GMAC_SAMT1_ADDR_Msk (0xffffu << GMAC_SAMT1_ADDR_Pos) /**< \brief (GMAC_SAMT1) Specific Address 1 Mask */
+#define GMAC_SAMT1_ADDR(value) ((GMAC_SAMT1_ADDR_Msk & ((value) << GMAC_SAMT1_ADDR_Pos)))
+/* -------- GMAC_OTLO : (GMAC Offset: 0x100) Octets Transmitted [31:0] Register -------- */
+#define GMAC_OTLO_TXO_Pos 0
+#define GMAC_OTLO_TXO_Msk (0xffffffffu << GMAC_OTLO_TXO_Pos) /**< \brief (GMAC_OTLO) Transmitted Octets */
+/* -------- GMAC_OTHI : (GMAC Offset: 0x104) Octets Transmitted [47:32] Register -------- */
+#define GMAC_OTHI_TXO_Pos 0
+#define GMAC_OTHI_TXO_Msk (0xffffu << GMAC_OTHI_TXO_Pos) /**< \brief (GMAC_OTHI) Transmitted Octets */
+/* -------- GMAC_FT : (GMAC Offset: 0x108) Frames Transmitted Register -------- */
+#define GMAC_FT_FTX_Pos 0
+#define GMAC_FT_FTX_Msk (0xffffffffu << GMAC_FT_FTX_Pos) /**< \brief (GMAC_FT) Frames Transmitted without Error */
+/* -------- GMAC_BCFT : (GMAC Offset: 0x10C) Broadcast Frames Transmitted Register -------- */
+#define GMAC_BCFT_BFTX_Pos 0
+#define GMAC_BCFT_BFTX_Msk (0xffffffffu << GMAC_BCFT_BFTX_Pos) /**< \brief (GMAC_BCFT) Broadcast Frames Transmitted without Error */
+/* -------- GMAC_MFT : (GMAC Offset: 0x110) Multicast Frames Transmitted Register -------- */
+#define GMAC_MFT_MFTX_Pos 0
+#define GMAC_MFT_MFTX_Msk (0xffffffffu << GMAC_MFT_MFTX_Pos) /**< \brief (GMAC_MFT) Multicast Frames Transmitted without Error */
+/* -------- GMAC_PFT : (GMAC Offset: 0x114) Pause Frames Transmitted Register -------- */
+#define GMAC_PFT_PFTX_Pos 0
+#define GMAC_PFT_PFTX_Msk (0xffffu << GMAC_PFT_PFTX_Pos) /**< \brief (GMAC_PFT) Pause Frames Transmitted Register */
+/* -------- GMAC_BFT64 : (GMAC Offset: 0x118) 64 Byte Frames Transmitted Register -------- */
+#define GMAC_BFT64_NFTX_Pos 0
+#define GMAC_BFT64_NFTX_Msk (0xffffffffu << GMAC_BFT64_NFTX_Pos) /**< \brief (GMAC_BFT64) 64 Byte Frames Transmitted without Error */
+/* -------- GMAC_TBFT127 : (GMAC Offset: 0x11C) 65 to 127 Byte Frames Transmitted Register -------- */
+#define GMAC_TBFT127_NFTX_Pos 0
+#define GMAC_TBFT127_NFTX_Msk (0xffffffffu << GMAC_TBFT127_NFTX_Pos) /**< \brief (GMAC_TBFT127) 65 to 127 Byte Frames Transmitted without Error */
+/* -------- GMAC_TBFT255 : (GMAC Offset: 0x120) 128 to 255 Byte Frames Transmitted Register -------- */
+#define GMAC_TBFT255_NFTX_Pos 0
+#define GMAC_TBFT255_NFTX_Msk (0xffffffffu << GMAC_TBFT255_NFTX_Pos) /**< \brief (GMAC_TBFT255) 128 to 255 Byte Frames Transmitted without Error */
+/* -------- GMAC_TBFT511 : (GMAC Offset: 0x124) 256 to 511 Byte Frames Transmitted Register -------- */
+#define GMAC_TBFT511_NFTX_Pos 0
+#define GMAC_TBFT511_NFTX_Msk (0xffffffffu << GMAC_TBFT511_NFTX_Pos) /**< \brief (GMAC_TBFT511) 256 to 511 Byte Frames Transmitted without Error */
+/* -------- GMAC_TBFT1023 : (GMAC Offset: 0x128) 512 to 1023 Byte Frames Transmitted Register -------- */
+#define GMAC_TBFT1023_NFTX_Pos 0
+#define GMAC_TBFT1023_NFTX_Msk (0xffffffffu << GMAC_TBFT1023_NFTX_Pos) /**< \brief (GMAC_TBFT1023) 512 to 1023 Byte Frames Transmitted without Error */
+/* -------- GMAC_TBFT1518 : (GMAC Offset: 0x12C) 1024 to 1518 Byte Frames Transmitted Register -------- */
+#define GMAC_TBFT1518_NFTX_Pos 0
+#define GMAC_TBFT1518_NFTX_Msk (0xffffffffu << GMAC_TBFT1518_NFTX_Pos) /**< \brief (GMAC_TBFT1518) 1024 to 1518 Byte Frames Transmitted without Error */
+/* -------- GMAC_GTBFT1518 : (GMAC Offset: 0x130) Greater Than 1518 Byte Frames Transmitted Register -------- */
+#define GMAC_GTBFT1518_NFTX_Pos 0
+#define GMAC_GTBFT1518_NFTX_Msk (0xffffffffu << GMAC_GTBFT1518_NFTX_Pos) /**< \brief (GMAC_GTBFT1518) Greater than 1518 Byte Frames Transmitted without Error */
+/* -------- GMAC_TUR : (GMAC Offset: 0x134) Transmit Under Runs Register -------- */
+#define GMAC_TUR_TXUNR_Pos 0
+#define GMAC_TUR_TXUNR_Msk (0x3ffu << GMAC_TUR_TXUNR_Pos) /**< \brief (GMAC_TUR) Transmit Under Runs */
+/* -------- GMAC_SCF : (GMAC Offset: 0x138) Single Collision Frames Register -------- */
+#define GMAC_SCF_SCOL_Pos 0
+#define GMAC_SCF_SCOL_Msk (0x3ffffu << GMAC_SCF_SCOL_Pos) /**< \brief (GMAC_SCF) Single Collision */
+/* -------- GMAC_MCF : (GMAC Offset: 0x13C) Multiple Collision Frames Register -------- */
+#define GMAC_MCF_MCOL_Pos 0
+#define GMAC_MCF_MCOL_Msk (0x3ffffu << GMAC_MCF_MCOL_Pos) /**< \brief (GMAC_MCF) Multiple Collision */
+/* -------- GMAC_EC : (GMAC Offset: 0x140) Excessive Collisions Register -------- */
+#define GMAC_EC_XCOL_Pos 0
+#define GMAC_EC_XCOL_Msk (0x3ffu << GMAC_EC_XCOL_Pos) /**< \brief (GMAC_EC) Excessive Collisions */
+/* -------- GMAC_LC : (GMAC Offset: 0x144) Late Collisions Register -------- */
+#define GMAC_LC_LCOL_Pos 0
+#define GMAC_LC_LCOL_Msk (0x3ffu << GMAC_LC_LCOL_Pos) /**< \brief (GMAC_LC) Late Collisions */
+/* -------- GMAC_DTF : (GMAC Offset: 0x148) Deferred Transmission Frames Register -------- */
+#define GMAC_DTF_DEFT_Pos 0
+#define GMAC_DTF_DEFT_Msk (0x3ffffu << GMAC_DTF_DEFT_Pos) /**< \brief (GMAC_DTF) Deferred Transmission */
+/* -------- GMAC_CSE : (GMAC Offset: 0x14C) Carrier Sense Errors Register -------- */
+#define GMAC_CSE_CSR_Pos 0
+#define GMAC_CSE_CSR_Msk (0x3ffu << GMAC_CSE_CSR_Pos) /**< \brief (GMAC_CSE) Carrier Sense Error */
+/* -------- GMAC_ORLO : (GMAC Offset: 0x150) Octets Received [31:0] Received -------- */
+#define GMAC_ORLO_RXO_Pos 0
+#define GMAC_ORLO_RXO_Msk (0xffffffffu << GMAC_ORLO_RXO_Pos) /**< \brief (GMAC_ORLO) Received Octets */
+/* -------- GMAC_ORHI : (GMAC Offset: 0x154) Octets Received [47:32] Received -------- */
+#define GMAC_ORHI_RXO_Pos 0
+#define GMAC_ORHI_RXO_Msk (0xffffu << GMAC_ORHI_RXO_Pos) /**< \brief (GMAC_ORHI) Received Octets */
+/* -------- GMAC_FR : (GMAC Offset: 0x158) Frames Received Register -------- */
+#define GMAC_FR_FRX_Pos 0
+#define GMAC_FR_FRX_Msk (0xffffffffu << GMAC_FR_FRX_Pos) /**< \brief (GMAC_FR) Frames Received without Error */
+/* -------- GMAC_BCFR : (GMAC Offset: 0x15C) Broadcast Frames Received Register -------- */
+#define GMAC_BCFR_BFRX_Pos 0
+#define GMAC_BCFR_BFRX_Msk (0xffffffffu << GMAC_BCFR_BFRX_Pos) /**< \brief (GMAC_BCFR) Broadcast Frames Received without Error */
+/* -------- GMAC_MFR : (GMAC Offset: 0x160) Multicast Frames Received Register -------- */
+#define GMAC_MFR_MFRX_Pos 0
+#define GMAC_MFR_MFRX_Msk (0xffffffffu << GMAC_MFR_MFRX_Pos) /**< \brief (GMAC_MFR) Multicast Frames Received without Error */
+/* -------- GMAC_PFR : (GMAC Offset: 0x164) Pause Frames Received Register -------- */
+#define GMAC_PFR_PFRX_Pos 0
+#define GMAC_PFR_PFRX_Msk (0xffffu << GMAC_PFR_PFRX_Pos) /**< \brief (GMAC_PFR) Pause Frames Received Register */
+/* -------- GMAC_BFR64 : (GMAC Offset: 0x168) 64 Byte Frames Received Register -------- */
+#define GMAC_BFR64_NFRX_Pos 0
+#define GMAC_BFR64_NFRX_Msk (0xffffffffu << GMAC_BFR64_NFRX_Pos) /**< \brief (GMAC_BFR64) 64 Byte Frames Received without Error */
+/* -------- GMAC_TBFR127 : (GMAC Offset: 0x16C) 65 to 127 Byte Frames Received Register -------- */
+#define GMAC_TBFR127_NFRX_Pos 0
+#define GMAC_TBFR127_NFRX_Msk (0xffffffffu << GMAC_TBFR127_NFRX_Pos) /**< \brief (GMAC_TBFR127) 65 to 127 Byte Frames Received without Error */
+/* -------- GMAC_TBFR255 : (GMAC Offset: 0x170) 128 to 255 Byte Frames Received Register -------- */
+#define GMAC_TBFR255_NFRX_Pos 0
+#define GMAC_TBFR255_NFRX_Msk (0xffffffffu << GMAC_TBFR255_NFRX_Pos) /**< \brief (GMAC_TBFR255) 128 to 255 Byte Frames Received without Error */
+/* -------- GMAC_TBFR511 : (GMAC Offset: 0x174) 256 to 511Byte Frames Received Register -------- */
+#define GMAC_TBFR511_NFRX_Pos 0
+#define GMAC_TBFR511_NFRX_Msk (0xffffffffu << GMAC_TBFR511_NFRX_Pos) /**< \brief (GMAC_TBFR511) 256 to 511 Byte Frames Received without Error */
+/* -------- GMAC_TBFR1023 : (GMAC Offset: 0x178) 512 to 1023 Byte Frames Received Register -------- */
+#define GMAC_TBFR1023_NFRX_Pos 0
+#define GMAC_TBFR1023_NFRX_Msk (0xffffffffu << GMAC_TBFR1023_NFRX_Pos) /**< \brief (GMAC_TBFR1023) 512 to 1023 Byte Frames Received without Error */
+/* -------- GMAC_TBFR1518 : (GMAC Offset: 0x17C) 1024 to 1518 Byte Frames Received Register -------- */
+#define GMAC_TBFR1518_NFRX_Pos 0
+#define GMAC_TBFR1518_NFRX_Msk (0xffffffffu << GMAC_TBFR1518_NFRX_Pos) /**< \brief (GMAC_TBFR1518) 1024 to 1518 Byte Frames Received without Error */
+/* -------- GMAC_TMXBFR : (GMAC Offset: 0x180) 1519 to Maximum Byte Frames Received Register -------- */
+#define GMAC_TMXBFR_NFRX_Pos 0
+#define GMAC_TMXBFR_NFRX_Msk (0xffffffffu << GMAC_TMXBFR_NFRX_Pos) /**< \brief (GMAC_TMXBFR) 1519 to Maximum Byte Frames Received without Error */
+/* -------- GMAC_UFR : (GMAC Offset: 0x184) Undersize Frames Received Register -------- */
+#define GMAC_UFR_UFRX_Pos 0
+#define GMAC_UFR_UFRX_Msk (0x3ffu << GMAC_UFR_UFRX_Pos) /**< \brief (GMAC_UFR) Undersize Frames Received */
+/* -------- GMAC_OFR : (GMAC Offset: 0x188) Oversize Frames Received Register -------- */
+#define GMAC_OFR_OFRX_Pos 0
+#define GMAC_OFR_OFRX_Msk (0x3ffu << GMAC_OFR_OFRX_Pos) /**< \brief (GMAC_OFR) Oversized Frames Received */
+/* -------- GMAC_JR : (GMAC Offset: 0x18C) Jabbers Received Register -------- */
+#define GMAC_JR_JRX_Pos 0
+#define GMAC_JR_JRX_Msk (0x3ffu << GMAC_JR_JRX_Pos) /**< \brief (GMAC_JR) Jabbers Received */
+/* -------- GMAC_FCSE : (GMAC Offset: 0x190) Frame Check Sequence Errors Register -------- */
+#define GMAC_FCSE_FCKR_Pos 0
+#define GMAC_FCSE_FCKR_Msk (0x3ffu << GMAC_FCSE_FCKR_Pos) /**< \brief (GMAC_FCSE) Frame Check Sequence Errors */
+/* -------- GMAC_LFFE : (GMAC Offset: 0x194) Length Field Frame Errors Register -------- */
+#define GMAC_LFFE_LFER_Pos 0
+#define GMAC_LFFE_LFER_Msk (0x3ffu << GMAC_LFFE_LFER_Pos) /**< \brief (GMAC_LFFE) Length Field Frame Errors */
+/* -------- GMAC_RSE : (GMAC Offset: 0x198) Receive Symbol Errors Register -------- */
+#define GMAC_RSE_RXSE_Pos 0
+#define GMAC_RSE_RXSE_Msk (0x3ffu << GMAC_RSE_RXSE_Pos) /**< \brief (GMAC_RSE) Receive Symbol Errors */
+/* -------- GMAC_AE : (GMAC Offset: 0x19C) Alignment Errors Register -------- */
+#define GMAC_AE_AER_Pos 0
+#define GMAC_AE_AER_Msk (0x3ffu << GMAC_AE_AER_Pos) /**< \brief (GMAC_AE) Alignment Errors */
+/* -------- GMAC_RRE : (GMAC Offset: 0x1A0) Receive Resource Errors Register -------- */
+#define GMAC_RRE_RXRER_Pos 0
+#define GMAC_RRE_RXRER_Msk (0x3ffffu << GMAC_RRE_RXRER_Pos) /**< \brief (GMAC_RRE) Receive Resource Errors */
+/* -------- GMAC_ROE : (GMAC Offset: 0x1A4) Receive Overrun Register -------- */
+#define GMAC_ROE_RXOVR_Pos 0
+#define GMAC_ROE_RXOVR_Msk (0x3ffu << GMAC_ROE_RXOVR_Pos) /**< \brief (GMAC_ROE) Receive Overruns */
+/* -------- GMAC_IHCE : (GMAC Offset: 0x1A8) IP Header Checksum Errors Register -------- */
+#define GMAC_IHCE_HCKER_Pos 0
+#define GMAC_IHCE_HCKER_Msk (0xffu << GMAC_IHCE_HCKER_Pos) /**< \brief (GMAC_IHCE) IP Header Checksum Errors */
+/* -------- GMAC_TCE : (GMAC Offset: 0x1AC) TCP Checksum Errors Register -------- */
+#define GMAC_TCE_TCKER_Pos 0
+#define GMAC_TCE_TCKER_Msk (0xffu << GMAC_TCE_TCKER_Pos) /**< \brief (GMAC_TCE) TCP Checksum Errors */
+/* -------- GMAC_UCE : (GMAC Offset: 0x1B0) UDP Checksum Errors Register -------- */
+#define GMAC_UCE_UCKER_Pos 0
+#define GMAC_UCE_UCKER_Msk (0xffu << GMAC_UCE_UCKER_Pos) /**< \brief (GMAC_UCE) UDP Checksum Errors */
+/* -------- GMAC_TSSS : (GMAC Offset: 0x1C8) 1588 Timer Sync Strobe Seconds Register -------- */
+#define GMAC_TSSS_VTS_Pos 0
+#define GMAC_TSSS_VTS_Msk (0xffffffffu << GMAC_TSSS_VTS_Pos) /**< \brief (GMAC_TSSS) Value of Timer Seconds Register Capture */
+#define GMAC_TSSS_VTS(value) ((GMAC_TSSS_VTS_Msk & ((value) << GMAC_TSSS_VTS_Pos)))
+/* -------- GMAC_TSSN : (GMAC Offset: 0x1CC) 1588 Timer Sync Strobe Nanoseconds Register -------- */
+#define GMAC_TSSN_VTN_Pos 0
+#define GMAC_TSSN_VTN_Msk (0x3fffffffu << GMAC_TSSN_VTN_Pos) /**< \brief (GMAC_TSSN) Value Timer Nanoseconds Register Capture */
+#define GMAC_TSSN_VTN(value) ((GMAC_TSSN_VTN_Msk & ((value) << GMAC_TSSN_VTN_Pos)))
+/* -------- GMAC_TS : (GMAC Offset: 0x1D0) 1588 Timer Seconds Register -------- */
+#define GMAC_TS_TCS_Pos 0
+#define GMAC_TS_TCS_Msk (0xffffffffu << GMAC_TS_TCS_Pos) /**< \brief (GMAC_TS) Timer Count in Seconds */
+#define GMAC_TS_TCS(value) ((GMAC_TS_TCS_Msk & ((value) << GMAC_TS_TCS_Pos)))
+/* -------- GMAC_TN : (GMAC Offset: 0x1D4) 1588 Timer Nanoseconds Register -------- */
+#define GMAC_TN_TNS_Pos 0
+#define GMAC_TN_TNS_Msk (0x3fffffffu << GMAC_TN_TNS_Pos) /**< \brief (GMAC_TN) Timer Count in Nanoseconds */
+#define GMAC_TN_TNS(value) ((GMAC_TN_TNS_Msk & ((value) << GMAC_TN_TNS_Pos)))
+/* -------- GMAC_TA : (GMAC Offset: 0x1D8) 1588 Timer Adjust Register -------- */
+#define GMAC_TA_ITDT_Pos 0
+#define GMAC_TA_ITDT_Msk (0x3fffffffu << GMAC_TA_ITDT_Pos) /**< \brief (GMAC_TA) Increment/Decrement */
+#define GMAC_TA_ITDT(value) ((GMAC_TA_ITDT_Msk & ((value) << GMAC_TA_ITDT_Pos)))
+#define GMAC_TA_ADJ (0x1u << 31) /**< \brief (GMAC_TA) Adjust 1588 Timer */
+/* -------- GMAC_TI : (GMAC Offset: 0x1DC) 1588 Timer Increment Register -------- */
+#define GMAC_TI_CNS_Pos 0
+#define GMAC_TI_CNS_Msk (0xffu << GMAC_TI_CNS_Pos) /**< \brief (GMAC_TI) Count Nanoseconds */
+#define GMAC_TI_CNS(value) ((GMAC_TI_CNS_Msk & ((value) << GMAC_TI_CNS_Pos)))
+#define GMAC_TI_ACNS_Pos 8
+#define GMAC_TI_ACNS_Msk (0xffu << GMAC_TI_ACNS_Pos) /**< \brief (GMAC_TI) Alternative Count Nanoseconds */
+#define GMAC_TI_ACNS(value) ((GMAC_TI_ACNS_Msk & ((value) << GMAC_TI_ACNS_Pos)))
+#define GMAC_TI_NIT_Pos 16
+#define GMAC_TI_NIT_Msk (0xffu << GMAC_TI_NIT_Pos) /**< \brief (GMAC_TI) Number of Increments */
+#define GMAC_TI_NIT(value) ((GMAC_TI_NIT_Msk & ((value) << GMAC_TI_NIT_Pos)))
+/* -------- GMAC_EFTS : (GMAC Offset: 0x1E0) PTP Event Frame Transmitted Seconds -------- */
+#define GMAC_EFTS_RUD_Pos 0
+#define GMAC_EFTS_RUD_Msk (0xffffffffu << GMAC_EFTS_RUD_Pos) /**< \brief (GMAC_EFTS) Register Update */
+/* -------- GMAC_EFTN : (GMAC Offset: 0x1E4) PTP Event Frame Transmitted Nanoseconds -------- */
+#define GMAC_EFTN_RUD_Pos 0
+#define GMAC_EFTN_RUD_Msk (0x3fffffffu << GMAC_EFTN_RUD_Pos) /**< \brief (GMAC_EFTN) Register Update */
+/* -------- GMAC_EFRS : (GMAC Offset: 0x1E8) PTP Event Frame Received Seconds -------- */
+#define GMAC_EFRS_RUD_Pos 0
+#define GMAC_EFRS_RUD_Msk (0xffffffffu << GMAC_EFRS_RUD_Pos) /**< \brief (GMAC_EFRS) Register Update */
+/* -------- GMAC_EFRN : (GMAC Offset: 0x1EC) PTP Event Frame Received Nanoseconds -------- */
+#define GMAC_EFRN_RUD_Pos 0
+#define GMAC_EFRN_RUD_Msk (0x3fffffffu << GMAC_EFRN_RUD_Pos) /**< \brief (GMAC_EFRN) Register Update */
+/* -------- GMAC_PEFTS : (GMAC Offset: 0x1F0) PTP Peer Event Frame Transmitted Seconds -------- */
+#define GMAC_PEFTS_RUD_Pos 0
+#define GMAC_PEFTS_RUD_Msk (0xffffffffu << GMAC_PEFTS_RUD_Pos) /**< \brief (GMAC_PEFTS) Register Update */
+/* -------- GMAC_PEFTN : (GMAC Offset: 0x1F4) PTP Peer Event Frame Transmitted Nanoseconds -------- */
+#define GMAC_PEFTN_RUD_Pos 0
+#define GMAC_PEFTN_RUD_Msk (0x3fffffffu << GMAC_PEFTN_RUD_Pos) /**< \brief (GMAC_PEFTN) Register Update */
+/* -------- GMAC_PEFRS : (GMAC Offset: 0x1F8) PTP Peer Event Frame Received Seconds -------- */
+#define GMAC_PEFRS_RUD_Pos 0
+#define GMAC_PEFRS_RUD_Msk (0xffffffffu << GMAC_PEFRS_RUD_Pos) /**< \brief (GMAC_PEFRS) Register Update */
+/* -------- GMAC_PEFRN : (GMAC Offset: 0x1FC) PTP Peer Event Frame Received Nanoseconds -------- */
+#define GMAC_PEFRN_RUD_Pos 0
+#define GMAC_PEFRN_RUD_Msk (0x3fffffffu << GMAC_PEFRN_RUD_Pos) /**< \brief (GMAC_PEFRN) Register Update */
+/* -------- GMAC_ISRPQ[7] : (GMAC Offset: 0x400) Interrupt Status Register Priority Queue -------- */
+#define GMAC_ISRPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_ISRPQ[7]) Receive Complete */
+#define GMAC_ISRPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_ISRPQ[7]) RX Used Bit Read */
+#define GMAC_ISRPQ_RLEX (0x1u << 5) /**< \brief (GMAC_ISRPQ[7]) Retry Limit Exceeded or Late Collision */
+#define GMAC_ISRPQ_TFC (0x1u << 6) /**< \brief (GMAC_ISRPQ[7]) Transmit Frame Corruption due to AHB error */
+#define GMAC_ISRPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_ISRPQ[7]) Transmit Complete */
+#define GMAC_ISRPQ_ROVR (0x1u << 10) /**< \brief (GMAC_ISRPQ[7]) Receive Overrun */
+#define GMAC_ISRPQ_HRESP (0x1u << 11) /**< \brief (GMAC_ISRPQ[7]) HRESP Not OK */
+/* -------- GMAC_TBQBAPQ[7] : (GMAC Offset: 0x440) Transmit Buffer Queue Base Address Priority Queue -------- */
+#define GMAC_TBQBAPQ_TXBQBA_Pos 2
+#define GMAC_TBQBAPQ_TXBQBA_Msk (0x3fu << GMAC_TBQBAPQ_TXBQBA_Pos) /**< \brief (GMAC_TBQBAPQ[7]) Transmit Buffer Queue Base Address */
+#define GMAC_TBQBAPQ_TXBQBA(value) ((GMAC_TBQBAPQ_TXBQBA_Msk & ((value) << GMAC_TBQBAPQ_TXBQBA_Pos)))
+/* -------- GMAC_RBQBAPQ[7] : (GMAC Offset: 0x480) Receive Buffer Queue Base Address Priority Queue -------- */
+#define GMAC_RBQBAPQ_RXBQBA_Pos 2
+#define GMAC_RBQBAPQ_RXBQBA_Msk (0x3fu << GMAC_RBQBAPQ_RXBQBA_Pos) /**< \brief (GMAC_RBQBAPQ[7]) Receive Buffer Queue Base Address */
+#define GMAC_RBQBAPQ_RXBQBA(value) ((GMAC_RBQBAPQ_RXBQBA_Msk & ((value) << GMAC_RBQBAPQ_RXBQBA_Pos)))
+/* -------- GMAC_RBSRPQ[7] : (GMAC Offset: 0x4A0) Receive Buffer Size Register Priority Queue -------- */
+#define GMAC_RBSRPQ_RBS_Pos 0
+#define GMAC_RBSRPQ_RBS_Msk (0xffffu << GMAC_RBSRPQ_RBS_Pos) /**< \brief (GMAC_RBSRPQ[7]) Receive Buffer Size */
+#define GMAC_RBSRPQ_RBS(value) ((GMAC_RBSRPQ_RBS_Msk & ((value) << GMAC_RBSRPQ_RBS_Pos)))
+/* -------- GMAC_ST1RPQ[16] : (GMAC Offset: 0x500) Screening Type1 Register Priority Queue -------- */
+#define GMAC_ST1RPQ_QNB_Pos 0
+#define GMAC_ST1RPQ_QNB_Msk (0xfu << GMAC_ST1RPQ_QNB_Pos) /**< \brief (GMAC_ST1RPQ[16]) Que Number (0->7) */
+#define GMAC_ST1RPQ_QNB(value) ((GMAC_ST1RPQ_QNB_Msk & ((value) << GMAC_ST1RPQ_QNB_Pos)))
+#define GMAC_ST1RPQ_DSTCM_Pos 4
+#define GMAC_ST1RPQ_DSTCM_Msk (0xffu << GMAC_ST1RPQ_DSTCM_Pos) /**< \brief (GMAC_ST1RPQ[16]) Differentiated Services or Traffic Class Match */
+#define GMAC_ST1RPQ_DSTCM(value) ((GMAC_ST1RPQ_DSTCM_Msk & ((value) << GMAC_ST1RPQ_DSTCM_Pos)))
+#define GMAC_ST1RPQ_UDPM_Pos 12
+#define GMAC_ST1RPQ_UDPM_Msk (0xffffu << GMAC_ST1RPQ_UDPM_Pos) /**< \brief (GMAC_ST1RPQ[16]) UDP Port Match */
+#define GMAC_ST1RPQ_UDPM(value) ((GMAC_ST1RPQ_UDPM_Msk & ((value) << GMAC_ST1RPQ_UDPM_Pos)))
+#define GMAC_ST1RPQ_DSTCE (0x1u << 28) /**< \brief (GMAC_ST1RPQ[16]) Differentiated Services or Traffic Class Match Enable */
+#define GMAC_ST1RPQ_UDPE (0x1u << 29) /**< \brief (GMAC_ST1RPQ[16]) UDP Port Match Enable */
+/* -------- GMAC_ST2RPQ[16] : (GMAC Offset: 0x540) Screening Type2 Register Priority Queue -------- */
+#define GMAC_ST2RPQ_QNB_Pos 0
+#define GMAC_ST2RPQ_QNB_Msk (0xfu << GMAC_ST2RPQ_QNB_Pos) /**< \brief (GMAC_ST2RPQ[16]) Que Number (0->7) */
+#define GMAC_ST2RPQ_QNB(value) ((GMAC_ST2RPQ_QNB_Msk & ((value) << GMAC_ST2RPQ_QNB_Pos)))
+#define GMAC_ST2RPQ_VLANP_Pos 4
+#define GMAC_ST2RPQ_VLANP_Msk (0xfu << GMAC_ST2RPQ_VLANP_Pos) /**< \brief (GMAC_ST2RPQ[16]) VLAN Priority */
+#define GMAC_ST2RPQ_VLANP(value) ((GMAC_ST2RPQ_VLANP_Msk & ((value) << GMAC_ST2RPQ_VLANP_Pos)))
+#define GMAC_ST2RPQ_VLANE (0x1u << 8) /**< \brief (GMAC_ST2RPQ[16]) VLAN Enable */
+/* -------- GMAC_IERPQ[7] : (GMAC Offset: 0x600) Interrupt Enable Register Priority Queue -------- */
+#define GMAC_IERPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_IERPQ[7]) Receive Complete */
+#define GMAC_IERPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_IERPQ[7]) RX Used Bit Read */
+#define GMAC_IERPQ_RLEX (0x1u << 5) /**< \brief (GMAC_IERPQ[7]) Retry Limit Exceeded or Late Collision */
+#define GMAC_IERPQ_TFC (0x1u << 6) /**< \brief (GMAC_IERPQ[7]) Transmit Frame Corruption due to AHB error */
+#define GMAC_IERPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_IERPQ[7]) Transmit Complete */
+#define GMAC_IERPQ_ROVR (0x1u << 10) /**< \brief (GMAC_IERPQ[7]) Receive Overrun */
+#define GMAC_IERPQ_HRESP (0x1u << 11) /**< \brief (GMAC_IERPQ[7]) HRESP Not OK */
+/* -------- GMAC_IDRPQ[7] : (GMAC Offset: 0x620) Interrupt Disable Register Priority Queue -------- */
+#define GMAC_IDRPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_IDRPQ[7]) Receive Complete */
+#define GMAC_IDRPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_IDRPQ[7]) RX Used Bit Read */
+#define GMAC_IDRPQ_RLEX (0x1u << 5) /**< \brief (GMAC_IDRPQ[7]) Retry Limit Exceeded or Late Collision */
+#define GMAC_IDRPQ_TFC (0x1u << 6) /**< \brief (GMAC_IDRPQ[7]) Transmit Frame Corruption due to AHB error */
+#define GMAC_IDRPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_IDRPQ[7]) Transmit Complete */
+#define GMAC_IDRPQ_ROVR (0x1u << 10) /**< \brief (GMAC_IDRPQ[7]) Receive Overrun */
+#define GMAC_IDRPQ_HRESP (0x1u << 11) /**< \brief (GMAC_IDRPQ[7]) HRESP Not OK */
+/* -------- GMAC_IMRPQ[7] : (GMAC Offset: 0x640) Interrupt Mask Register Priority Queue -------- */
+#define GMAC_IMRPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_IMRPQ[7]) Receive Complete */
+#define GMAC_IMRPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_IMRPQ[7]) RX Used Bit Read */
+#define GMAC_IMRPQ_RLEX (0x1u << 5) /**< \brief (GMAC_IMRPQ[7]) Retry Limit Exceeded or Late Collision */
+#define GMAC_IMRPQ_AHB (0x1u << 6) /**< \brief (GMAC_IMRPQ[7]) AHB Error */
+#define GMAC_IMRPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_IMRPQ[7]) Transmit Complete */
+#define GMAC_IMRPQ_ROVR (0x1u << 10) /**< \brief (GMAC_IMRPQ[7]) Receive Overrun */
+#define GMAC_IMRPQ_HRESP (0x1u << 11) /**< \brief (GMAC_IMRPQ[7]) HRESP Not OK */
+
+/*@}*/
+
+
+#endif /* _SAM4E_GMAC_COMPONENT_ */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.c
new file mode 100644
index 000000000..fe9e2960f
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.c
@@ -0,0 +1,454 @@
+ /**
+ * \file
+ *
+ * \brief API driver for KSZ8051MNL PHY component.
+ *
+ * Copyright (c) 2013 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "FreeRTOSIPConfig.h"
+
+#include "ethernet_phy.h"
+#include "instance/gmac.h"
+
+/// @cond 0
+/**INDENT-OFF**/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**INDENT-ON**/
+/// @endcond
+
+/**
+ * \defgroup ksz8051mnl_ethernet_phy_group PHY component (KSZ8051MNL)
+ *
+ * Driver for the ksz8051mnl component. This driver provides access to the main
+ * features of the PHY.
+ *
+ * \section dependencies Dependencies
+ * This driver depends on the following modules:
+ * - \ref gmac_group Ethernet Media Access Controller (GMAC) module.
+ *
+ * @{
+ */
+
+SPhyProps phyProps;
+
+/* Max PHY number */
+#define ETH_PHY_MAX_ADDR 31
+
+/* Ethernet PHY operation max retry count */
+#define ETH_PHY_RETRY_MAX 1000000
+
+/* Ethernet PHY operation timeout */
+#define ETH_PHY_TIMEOUT 10
+
+/**
+ * \brief Find a valid PHY Address ( from addrStart to 31 ).
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_addr PHY address.
+ * \param uc_start_addr Start address of the PHY to be searched.
+ *
+ * \return 0xFF when no valid PHY address is found.
+ */
+int ethernet_phy_addr = 0;
+static uint8_t ethernet_phy_find_valid(Gmac *p_gmac, uint8_t uc_phy_addr,
+ uint8_t uc_start_addr)
+{
+ uint32_t ul_value = 0;
+ uint8_t uc_cnt;
+ uint8_t uc_phy_address = uc_phy_addr;
+
+ gmac_enable_management(p_gmac, true);
+/*
+#define GMII_OUI_MSB 0x0022
+#define GMII_OUI_LSB 0x05
+
+PHYID1 = 0x0022
+PHYID2 = 0x1550
+0001_0101_0101_0000 = 0x1550 <= mask should be 0xFFF0
+*/
+ /* Check the current PHY address */
+ gmac_phy_read(p_gmac, uc_phy_addr, GMII_PHYID1, &ul_value);
+
+ /* Find another one */
+ if (ul_value != GMII_OUI_MSB) {
+ ethernet_phy_addr = 0xFF;
+ for (uc_cnt = uc_start_addr; uc_cnt <= ETH_PHY_MAX_ADDR; uc_cnt++) {
+ uc_phy_address = (uc_phy_address + 1) & 0x1F;
+ ul_value = 0;
+ gmac_phy_read(p_gmac, uc_phy_address, GMII_PHYID1, &ul_value);
+ if (ul_value == GMII_OUI_MSB) {
+ ethernet_phy_addr = uc_phy_address;
+ break;
+ }
+ }
+ }
+
+ gmac_enable_management(p_gmac, false);
+
+ if (ethernet_phy_addr != 0xFF) {
+ gmac_phy_read(p_gmac, uc_phy_address, GMII_BMSR, &ul_value);
+ }
+ return ethernet_phy_addr;
+}
+
+
+/**
+ * \brief Perform a HW initialization to the PHY and set up clocks.
+ *
+ * This should be called only once to initialize the PHY pre-settings.
+ * The PHY address is the reset status of CRS, RXD[3:0] (the emacPins' pullups).
+ * The COL pin is used to select MII mode on reset (pulled up for Reduced MII).
+ * The RXDV pin is used to select test mode on reset (pulled up for test mode).
+ * The above pins should be predefined for corresponding settings in resetPins.
+ * The GMAC peripheral pins are configured after the reset is done.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_addr PHY address.
+ * \param ul_mck GMAC MCK.
+ *
+ * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
+ */
+uint8_t ethernet_phy_init(Gmac *p_gmac, uint8_t uc_phy_addr, uint32_t mck)
+{
+ uint8_t uc_rc = GMAC_TIMEOUT;
+ uint8_t uc_phy;
+
+ ethernet_phy_reset(GMAC,uc_phy_addr);
+
+ /* Configure GMAC runtime clock */
+ uc_rc = gmac_set_mdc_clock(p_gmac, mck);
+ if (uc_rc != GMAC_OK) {
+ return 0;
+ }
+
+ /* Check PHY Address */
+ uc_phy = ethernet_phy_find_valid(p_gmac, uc_phy_addr, 0);
+ if (uc_phy == 0xFF) {
+ return 0;
+ }
+ if (uc_phy != uc_phy_addr) {
+ ethernet_phy_reset(p_gmac, uc_phy_addr);
+ }
+ phy_props.phy_chn = uc_phy;
+ return uc_phy;
+}
+
+
+/**
+ * \brief Get the Link & speed settings, and automatically set up the GMAC with the
+ * settings.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_addr PHY address.
+ * \param uc_apply_setting_flag Set to 0 to not apply the PHY configurations, else to apply.
+ *
+ * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
+ */
+uint8_t ethernet_phy_set_link(Gmac *p_gmac, uint8_t uc_phy_addr,
+ uint8_t uc_apply_setting_flag)
+{
+ uint32_t ul_stat1;
+ uint32_t ul_stat2;
+ uint8_t uc_phy_address, uc_speed = true, uc_fd = true;
+ uint8_t uc_rc = GMAC_TIMEOUT;
+
+ gmac_enable_management(p_gmac, true);
+
+ uc_phy_address = uc_phy_addr;
+
+ uc_rc = gmac_phy_read(p_gmac, uc_phy_address, GMII_BMSR, &ul_stat1);
+ if (uc_rc != GMAC_OK) {
+ /* Disable PHY management and start the GMAC transfer */
+ gmac_enable_management(p_gmac, false);
+
+ return uc_rc;
+ }
+ if ((ul_stat1 & GMII_LINK_STATUS) == 0) {
+ /* Disable PHY management and start the GMAC transfer */
+ gmac_enable_management(p_gmac, false);
+
+ return GMAC_INVALID;
+ }
+
+ if (uc_apply_setting_flag == 0) {
+ /* Disable PHY management and start the GMAC transfer */
+ gmac_enable_management(p_gmac, false);
+
+ return uc_rc;
+ }
+
+ /* Read advertisement */
+ uc_rc = gmac_phy_read(p_gmac, uc_phy_address, GMII_ANAR, &ul_stat2);
+phy_props.phy_stat1 = ul_stat1;
+phy_props.phy_stat2 = ul_stat2;
+ if (uc_rc != GMAC_OK) {
+ /* Disable PHY management and start the GMAC transfer */
+ gmac_enable_management(p_gmac, false);
+
+ return uc_rc;
+ }
+
+ if ((ul_stat1 & GMII_100BASE_TX_FD) && (ul_stat2 & GMII_100TX_FDX)) {
+ /* Set GMAC for 100BaseTX and Full Duplex */
+ uc_speed = true;
+ uc_fd = true;
+ } else
+ if ((ul_stat1 & GMII_100BASE_T4_HD) && (ul_stat2 & GMII_100TX_HDX)) {
+ /* Set MII for 100BaseTX and Half Duplex */
+ uc_speed = true;
+ uc_fd = false;
+ } else
+ if ((ul_stat1 & GMII_10BASE_T_FD) && (ul_stat2 & GMII_10_FDX)) {
+ /* Set MII for 10BaseT and Full Duplex */
+ uc_speed = false;
+ uc_fd = true;
+ } else
+ if ((ul_stat1 & GMII_10BASE_T_HD) && (ul_stat2 & GMII_10_HDX)) {
+ /* Set MII for 10BaseT and Half Duplex */
+ uc_speed = false;
+ uc_fd = false;
+ }
+
+ gmac_set_speed(p_gmac, uc_speed);
+ gmac_enable_full_duplex(p_gmac, uc_fd);
+
+ /* Start the GMAC transfers */
+ gmac_enable_management(p_gmac, false);
+ return uc_rc;
+}
+
+PhyProps_t phy_props;
+
+/**
+ * \brief Issue an auto negotiation of the PHY.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_addr PHY address.
+ *
+ * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
+ */
+uint8_t ethernet_phy_auto_negotiate(Gmac *p_gmac, uint8_t uc_phy_addr)
+{
+ uint32_t ul_retry_max = ETH_PHY_RETRY_MAX;
+ uint32_t ul_value;
+ uint32_t ul_phy_anar;
+ uint32_t ul_retry_count = 0;
+ uint8_t uc_speed = 0;
+ uint8_t uc_fd=0;
+ uint8_t uc_rc = GMAC_TIMEOUT;
+
+ gmac_enable_management(p_gmac, true);
+
+ /* Set up control register */
+ uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value);
+ if (uc_rc != GMAC_OK) {
+ gmac_enable_management(p_gmac, false);
+phy_props.phy_result = -1;
+ return uc_rc;
+ }
+
+ ul_value &= ~(uint32_t)GMII_AUTONEG; /* Remove auto-negotiation enable */
+ ul_value &= ~(uint32_t)(GMII_LOOPBACK | GMII_POWER_DOWN);
+ ul_value |= (uint32_t)GMII_ISOLATE; /* Electrically isolate PHY */
+ uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);
+ if (uc_rc != GMAC_OK) {
+ gmac_enable_management(p_gmac, false);
+phy_props.phy_result = -2;
+ return uc_rc;
+ }
+
+ /*
+ * Set the Auto_negotiation Advertisement Register.
+ * MII advertising for Next page.
+ * 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3.
+ */
+ ul_phy_anar = GMII_100TX_FDX | GMII_100TX_HDX | GMII_10_FDX | GMII_10_HDX |
+ GMII_AN_IEEE_802_3;
+ uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_ANAR, ul_phy_anar);
+ if (uc_rc != GMAC_OK) {
+ gmac_enable_management(p_gmac, false);
+phy_props.phy_result = -3;
+ return uc_rc;
+ }
+
+ /* Read & modify control register */
+ uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value);
+ if (uc_rc != GMAC_OK) {
+ gmac_enable_management(p_gmac, false);
+phy_props.phy_result = -4;
+ return uc_rc;
+ }
+
+ ul_value |= GMII_SPEED_SELECT | GMII_AUTONEG | GMII_DUPLEX_MODE;
+ uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);
+ if (uc_rc != GMAC_OK) {
+ gmac_enable_management(p_gmac, false);
+phy_props.phy_result = -5;
+ return uc_rc;
+ }
+
+ /* Restart auto negotiation */
+ ul_value |= (uint32_t)GMII_RESTART_AUTONEG;
+ ul_value &= ~(uint32_t)GMII_ISOLATE;
+ uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);
+ if (uc_rc != GMAC_OK) {
+ gmac_enable_management(p_gmac, false);
+phy_props.phy_result = -6;
+ return uc_rc;
+ }
+
+ /* Check if auto negotiation is completed */
+ while (1) {
+ uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMSR, &ul_value);
+ if (uc_rc != GMAC_OK) {
+ gmac_enable_management(p_gmac, false);
+phy_props.phy_result = -7;
+ return uc_rc;
+ }
+ /* Done successfully */
+ if (ul_value & GMII_AUTONEG_COMP) {
+ break;
+ }
+
+ /* Timeout check */
+ if (ul_retry_max) {
+ if (++ul_retry_count >= ul_retry_max) {
+ gmac_enable_management(p_gmac, false);
+phy_props.phy_result = -8;
+ return GMAC_TIMEOUT;
+ }
+ }
+ }
+
+ /* Get the auto negotiate link partner base page */
+ uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_PCR1, &phy_props.phy_params);
+ if (uc_rc != GMAC_OK) {
+ gmac_enable_management(p_gmac, false);
+phy_props.phy_result = -9;
+ return uc_rc;
+ }
+
+
+ /* Set up the GMAC link speed */
+ if ((ul_phy_anar & phy_props.phy_params) & GMII_100TX_FDX) {
+ /* Set MII for 100BaseTX and Full Duplex */
+ uc_speed = true;
+ uc_fd = true;
+ } else if ((ul_phy_anar & phy_props.phy_params) & GMII_10_FDX) {
+ /* Set MII for 10BaseT and Full Duplex */
+ uc_speed = false;
+ uc_fd = true;
+ } else if ((ul_phy_anar & phy_props.phy_params) & GMII_100TX_HDX) {
+ /* Set MII for 100BaseTX and half Duplex */
+ uc_speed = true;
+ uc_fd = false;
+ } else if ((ul_phy_anar & phy_props.phy_params) & GMII_10_HDX) {
+ /* Set MII for 10BaseT and half Duplex */
+ uc_speed = false;
+ uc_fd = false;
+ }
+
+ gmac_set_speed(p_gmac, uc_speed);
+ gmac_enable_full_duplex(p_gmac, uc_fd);
+
+ /* Select Media Independent Interface type */
+ gmac_select_mii_mode(p_gmac, ETH_PHY_MODE);
+
+ gmac_enable_transmit(GMAC, true);
+ gmac_enable_receive(GMAC, true);
+
+ gmac_enable_management(p_gmac, false);
+phy_props.phy_result = 1;
+ return uc_rc;
+}
+
+/**
+ * \brief Issue a SW reset to reset all registers of the PHY.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_addr PHY address.
+ *
+ * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
+ */
+uint8_t ethernet_phy_reset(Gmac *p_gmac, uint8_t uc_phy_addr)
+{
+ uint32_t ul_bmcr = GMII_RESET;
+ uint8_t uc_phy_address = uc_phy_addr;
+ uint32_t ul_timeout = ETH_PHY_TIMEOUT;
+ uint8_t uc_rc = GMAC_TIMEOUT;
+
+ gmac_enable_management(p_gmac, true);
+
+ ul_bmcr = GMII_RESET;
+ gmac_phy_write(p_gmac, uc_phy_address, GMII_BMCR, ul_bmcr);
+
+ do {
+ gmac_phy_read(p_gmac, uc_phy_address, GMII_BMCR, &ul_bmcr);
+ ul_timeout--;
+ } while ((ul_bmcr & GMII_RESET) && ul_timeout);
+
+ gmac_enable_management(p_gmac, false);
+
+ if (!ul_timeout) {
+ uc_rc = GMAC_OK;
+ }
+
+ return (uc_rc);
+}
+
+/// @cond 0
+/**INDENT-OFF**/
+#ifdef __cplusplus
+}
+#endif
+/**INDENT-ON**/
+/// @endcond
+
+/**
+ * \}
+ */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.h
new file mode 100644
index 000000000..8ea5fa0c7
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.h
@@ -0,0 +1,281 @@
+/**
+ * \file
+ *
+ * \brief KSZ8051MNL (Ethernet PHY) driver for SAM.
+ *
+ * Copyright (c) 2013 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#ifndef ETHERNET_PHY_H_INCLUDED
+#define ETHERNET_PHY_H_INCLUDED
+
+#include "compiler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// IEEE defined Registers
+#define GMII_BMCR 0x00 // Basic Control
+#define GMII_BMSR 0x01 // Basic Status
+#define GMII_PHYID1 0x02 // PHY Idendifier 1
+#define GMII_PHYID2 0x03 // PHY Idendifier 2
+#define GMII_ANAR 0x04 // Auto_Negotiation Advertisement
+#define GMII_ANLPAR 0x05 // Auto_negotiation Link Partner Ability
+#define GMII_ANER 0x06 // Auto-negotiation Expansion
+#define GMII_ANNPR 0x07 // Auto-negotiation Next Page
+#define GMII_ANLPNPAR 0x08 // Link Partner Next Page Ability
+//#define GMII_1000BTCR 9 // 1000Base-T Control // Reserved
+//#define GMII_1000BTSR 10 // 1000Base-T Status // Reserved
+#define GMII_AFECR1 0x11 // AFE Control 1
+//#define GMII_ERDWR 12 // Extend Register - Data Write Register
+//#define GMII_ERDRR 13 // Extend Register - Data Read Register
+//14 reserved
+#define GMII_RXERCR 0x15 // RXER Counter
+
+ #define PHY_REG_01_BMSR 0x01 // Basic mode status register
+ #define PHY_REG_02_PHYSID1 0x02 // PHYS ID 1
+ #define PHY_REG_03_PHYSID2 0x03 // PHYS ID 2
+ #define PHY_REG_04_ADVERTISE 0x04 // Advertisement control reg
+ #define PHY_REG_05_LPA 0x05 // Link partner ability reg
+ #define PHY_REG_06_ANER 0x06 // 6 RW Auto-Negotiation Expansion Register
+ #define PHY_REG_07_ANNPTR 0x07 // 7 RW Auto-Negotiation Next Page TX
+ #define PHY_REG_08_RESERVED0 0x08 // 0x08..0x0Fh 8-15 RW RESERVED
+
+ #define PHY_REG_10_PHYSTS 0x10 // 16 RO PHY Status Register
+ #define PHY_REG_11_MICR 0x11 // 17 RW MII Interrupt Control Register
+ #define PHY_REG_12_MISR 0x12 // 18 RO MII Interrupt Status Register
+ #define PHY_REG_13_RESERVED1 0x13 // 19 RW RESERVED
+ #define PHY_REG_14_FCSCR 0x14 // 20 RO False Carrier Sense Counter Register
+ #define PHY_REG_15_RECR 0x15 // 21 RO Receive Error Counter Register
+ #define PHY_REG_16_PCSR 0x16 // 22 RW PCS Sub-Layer Configuration and Status Register
+ #define PHY_REG_17_RBR 0x17 // 23 RW RMII and Bypass Register
+ #define PHY_REG_18_LEDCR 0x18 // 24 RW LED Direct Control Register
+ #define PHY_REG_19_PHYCR 0x19 // 25 RW PHY Control Register
+ #define PHY_REG_1A_10BTSCR 0x1A // 26 RW 10Base-T Status/Control Register
+ #define PHY_REG_1B_CDCTRL1 0x1B // 27 RW CD Test Control Register and BIST Extensions Register
+ #define PHY_REG_1B_INT_CTRL 0x1B // 27 RW KSZ8041NL interrupt control
+ #define PHY_REG_1C_RESERVED2 0x1C // 28 RW RESERVED
+ #define PHY_REG_1D_EDCR 0x1D // 29 RW Energy Detect Control Register
+ #define PHY_REG_1E_RESERVED3 0x1E //
+ #define PHY_REG_1F_RESERVED4 0x1F // 30-31 RW RESERVED
+
+ #define PHY_REG_1E_PHYCR_1 0x1E //
+ #define PHY_REG_1F_PHYCR_2 0x1F //
+
+ #define PHY_SPEED_10 1
+ #define PHY_SPEED_100 2
+ #define PHY_SPEED_AUTO (PHY_SPEED_10|PHY_SPEED_100)
+
+ #define PHY_MDIX_DIRECT 1
+ #define PHY_MDIX_CROSSED 2
+ #define PHY_MDIX_AUTO (PHY_MDIX_CROSSED|PHY_MDIX_DIRECT)
+
+ #define PHY_DUPLEX_HALF 1
+ #define PHY_DUPLEX_FULL 2
+ #define PHY_DUPLEX_AUTO (PHY_DUPLEX_FULL|PHY_DUPLEX_HALF)
+
+ typedef struct _SPhyProps {
+ unsigned char speed;
+ unsigned char mdix;
+ unsigned char duplex;
+ unsigned char spare;
+ } SPhyProps;
+
+ const char *phyPrintable (const SPhyProps *apProps);
+
+ extern SPhyProps phyProps;
+
+#define GMII_OMSOR 0x16 // Operation Mode Strap Override
+#define GMII_OMSSR 0x17 // Operation Mode Strap Status
+#define GMII_ECR 0x18 // Expanded Control
+//#define GMII_DPPSR 19 // Digital PMA/PCS Status
+//20 reserved
+//#define GMII_RXERCR 21 // RXER Counter Register
+//22-26 reserved
+#define GMII_ICSR 0x1B // Interrupt Control/Status
+//#define GMII_DDC1R 28 // Digital Debug Control 1 Register
+#define GMII_LCSR 0x1D // LinkMD Control/Status
+
+//29-30 reserved
+#define GMII_PCR1 0x1E // PHY Control 1
+#define GMII_PCR2 0x1F // PHY Control 2
+
+/*
+//Extend Registers
+#define GMII_CCR 256 // Common Control Register
+#define GMII_SSR 257 // Strap Status Register
+#define GMII_OMSOR 258 // Operation Mode Strap Override Register
+#define GMII_OMSSR 259 // Operation Mode Strap Status Register
+#define GMII_RCCPSR 260 // RGMII Clock and Control Pad Skew Register
+#define GMII_RRDPSR 261 // RGMII RX Data Pad Skew Register
+#define GMII_ATR 263 // Analog Test Register
+*/
+
+
+// Bit definitions: GMII_BMCR 0x00 Basic Control
+#define GMII_RESET (1 << 15) // 1= Software Reset; 0=Normal Operation
+#define GMII_LOOPBACK (1 << 14) // 1=loopback Enabled; 0=Normal Operation
+#define GMII_SPEED_SELECT (1 << 13) // 1=100Mbps; 0=10Mbps
+#define GMII_AUTONEG (1 << 12) // Auto-negotiation Enable
+#define GMII_POWER_DOWN (1 << 11) // 1=Power down 0=Normal operation
+#define GMII_ISOLATE (1 << 10) // 1 = Isolates 0 = Normal operation
+#define GMII_RESTART_AUTONEG (1 << 9) // 1 = Restart auto-negotiation 0 = Normal operation
+#define GMII_DUPLEX_MODE (1 << 8) // 1 = Full duplex operation 0 = Normal operation
+#define GMII_COLLISION_TEST (1 << 7) // 1 = Enable COL test; 0 = Disable COL test
+//#define GMII_SPEED_SELECT_MSB (1 << 6) // Reserved
+// Reserved 6 to 0 // Read as 0, ignore on write
+
+// Bit definitions: GMII_BMSR 0x01 Basic Status
+#define GMII_100BASE_T4 (1 << 15) // 100BASE-T4 Capable
+#define GMII_100BASE_TX_FD (1 << 14) // 100BASE-TX Full Duplex Capable
+#define GMII_100BASE_T4_HD (1 << 13) // 100BASE-TX Half Duplex Capable
+#define GMII_10BASE_T_FD (1 << 12) // 10BASE-T Full Duplex Capable
+#define GMII_10BASE_T_HD (1 << 11) // 10BASE-T Half Duplex Capable
+// Reserved 10 to79 // Read as 0, ignore on write
+//#define GMII_EXTEND_STATUS (1 << 8) // 1 = Extend Status Information In Reg 15
+// Reserved 7
+#define GMII_MF_PREAMB_SUPPR (1 << 6) // MII Frame Preamble Suppression
+#define GMII_AUTONEG_COMP (1 << 5) // Auto-negotiation Complete
+#define GMII_REMOTE_FAULT (1 << 4) // Remote Fault
+#define GMII_AUTONEG_ABILITY (1 << 3) // Auto Configuration Ability
+#define GMII_LINK_STATUS (1 << 2) // Link Status
+#define GMII_JABBER_DETECT (1 << 1) // Jabber Detect
+#define GMII_EXTEND_CAPAB (1 << 0) // Extended Capability
+
+
+// Bit definitions: GMII_PHYID1 0x02 PHY Idendifier 1
+// Bit definitions: GMII_PHYID2 0x03 PHY Idendifier 2
+#define GMII_LSB_MASK 0x3F
+#define GMII_OUI_MSB 0x0022
+#define GMII_OUI_LSB 0x05
+
+
+// Bit definitions: GMII_ANAR 0x04 Auto_Negotiation Advertisement
+// Bit definitions: GMII_ANLPAR 0x05 Auto_negotiation Link Partner Ability
+#define GMII_NP (1 << 15) // Next page Indication
+// Reserved 7
+#define GMII_RF (1 << 13) // Remote Fault
+// Reserved 12 // Write as 0, ignore on read
+#define GMII_PAUSE_MASK (3 << 11) // 0,0 = No Pause 1,0 = Asymmetric Pause(link partner)
+ // 0,1 = Symmetric Pause 1,1 = Symmetric&Asymmetric Pause(local device)
+#define GMII_100T4 (1 << 9) // 100BASE-T4 Support
+#define GMII_100TX_FDX (1 << 8) // 100BASE-TX Full Duplex Support
+#define GMII_100TX_HDX (1 << 7) // 100BASE-TX Support
+#define GMII_10_FDX (1 << 6) // 10BASE-T Full Duplex Support
+#define GMII_10_HDX (1 << 5) // 10BASE-T Support
+// Selector 4 to 0 // Protocol Selection Bits
+#define GMII_AN_IEEE_802_3 0x0001 // [00001] = IEEE 802.3
+
+
+// Bit definitions: GMII_ANER 0x06 Auto-negotiation Expansion
+// Reserved 15 to 5 // Read as 0, ignore on write
+#define GMII_PDF (1 << 4) // Local Device Parallel Detection Fault
+#define GMII_LP_NP_ABLE (1 << 3) // Link Partner Next Page Able
+#define GMII_NP_ABLE (1 << 2) // Local Device Next Page Able
+#define GMII_PAGE_RX (1 << 1) // New Page Received
+#define GMII_LP_AN_ABLE (1 << 0) // Link Partner Auto-negotiation Able
+
+/**
+ * \brief Perform a HW initialization to the PHY and set up clocks.
+ *
+ * This should be called only once to initialize the PHY pre-settings.
+ * The PHY address is the reset status of CRS, RXD[3:0] (the GmacPins' pullups).
+ * The COL pin is used to select MII mode on reset (pulled up for Reduced MII).
+ * The RXDV pin is used to select test mode on reset (pulled up for test mode).
+ * The above pins should be predefined for corresponding settings in resetPins.
+ * The GMAC peripheral pins are configured after the reset is done.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_addr PHY address.
+ * \param ul_mck GMAC MCK.
+ *
+ * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
+ */
+uint8_t ethernet_phy_init(Gmac *p_gmac, uint8_t uc_phy_addr, uint32_t ul_mck);
+
+
+/**
+ * \brief Get the Link & speed settings, and automatically set up the GMAC with the
+ * settings.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_addr PHY address.
+ * \param uc_apply_setting_flag Set to 0 to not apply the PHY configurations, else to apply.
+ *
+ * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
+ */
+uint8_t ethernet_phy_set_link(Gmac *p_gmac, uint8_t uc_phy_addr,
+ uint8_t uc_apply_setting_flag);
+
+
+/**
+ * \brief Issue an auto negotiation of the PHY.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_addr PHY address.
+ *
+ * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
+ */
+uint8_t ethernet_phy_auto_negotiate(Gmac *p_gmac, uint8_t uc_phy_addr);
+
+/**
+ * \brief Issue a SW reset to reset all registers of the PHY.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_addr PHY address.
+ *
+ * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
+ */
+uint8_t ethernet_phy_reset(Gmac *p_gmac, uint8_t uc_phy_addr);
+
+typedef struct xPHY_PROPS {
+ signed char phy_result;
+ uint32_t phy_params;
+ uint32_t phy_stat1;
+ uint32_t phy_stat2;
+ unsigned char phy_chn;
+} PhyProps_t;
+extern PhyProps_t phy_props;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef ETHERNET_PHY_H_INCLUDED */
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c
new file mode 100644
index 000000000..fe73a73ac
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c
@@ -0,0 +1,945 @@
+ /**
+ * \file
+ *
+ * \brief GMAC (Ethernet MAC) driver for SAM.
+ *
+ * Copyright (c) 2013 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+#include "FreeRTOSIPConfig.h"
+
+#include "compiler.h"
+#include "instance/gmac.h"
+#include "ethernet_phy.h"
+
+/// @cond 0
+/**INDENT-OFF**/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**INDENT-ON**/
+/// @endcond
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (int)( sizeof(x) / sizeof(x)[0] )
+#endif
+/**
+ * \defgroup gmac_group Ethernet Media Access Controller
+ *
+ * See \ref gmac_quickstart.
+ *
+ * Driver for the GMAC (Ethernet Media Access Controller).
+ * This file contains basic functions for the GMAC, with support for all modes, settings
+ * and clock speeds.
+ *
+ * \section dependencies Dependencies
+ * This driver does not depend on other modules.
+ *
+ * @{
+ */
+
+/** TX descriptor lists */
+COMPILER_ALIGNED(8)
+static gmac_tx_descriptor_t gs_tx_desc[ GMAC_TX_BUFFERS ];
+#if( GMAC_USES_TX_CALLBACK != 0 )
+/** TX callback lists */
+static gmac_dev_tx_cb_t gs_tx_callback[ GMAC_TX_BUFFERS ];
+#endif
+/** RX descriptors lists */
+COMPILER_ALIGNED(8)
+static gmac_rx_descriptor_t gs_rx_desc[ GMAC_RX_BUFFERS ];
+
+#if( ipconfigZERO_COPY_TX_DRIVER == 0 )
+ /** Send Buffer. Section 3.6 of AMBA 2.0 spec states that burst should not cross the
+ * 1K Boundaries. Receive buffer manager write operations are burst of 2 words => 3 lsb bits
+ * of the address shall be set to 0.
+ */
+ COMPILER_ALIGNED(8)
+ static uint8_t gs_uc_tx_buffer[ GMAC_TX_BUFFERS * GMAC_TX_UNITSIZE ];
+#endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+/** Receive Buffer */
+COMPILER_ALIGNED(8)
+static uint8_t gs_uc_rx_buffer[ GMAC_RX_BUFFERS * GMAC_RX_UNITSIZE ];
+
+/**
+ * GMAC device memory management struct.
+ */
+typedef struct gmac_dev_mem {
+ /* Pointer to allocated buffer for RX. The address should be 8-byte aligned
+ and the size should be GMAC_RX_UNITSIZE * wRxSize. */
+ uint8_t *p_rx_buffer;
+ /* Pointer to allocated RX descriptor list. */
+ gmac_rx_descriptor_t *p_rx_dscr;
+ /* RX size, in number of registered units (RX descriptors). */
+ /* Increased size from 16- to 32-bits, because it's more efficient */
+ uint32_t us_rx_size;
+ /* Pointer to allocated buffer for TX. The address should be 8-byte aligned
+ and the size should be GMAC_TX_UNITSIZE * wTxSize. */
+ uint8_t *p_tx_buffer;
+ /* Pointer to allocated TX descriptor list. */
+ gmac_tx_descriptor_t *p_tx_dscr;
+ /* TX size, in number of registered units (TX descriptors). */
+ uint32_t us_tx_size;
+} gmac_dev_mem_t;
+
+/** Return count in buffer */
+#define CIRC_CNT( head, tail, size ) ( ( ( head ) - ( tail ) ) % ( size ) )
+
+/*
+ * Return space available, from 0 to size-1.
+ * Always leave one free char as a completely full buffer that has (head == tail),
+ * which is the same as empty.
+ */
+#define CIRC_SPACE( head, tail, size ) CIRC_CNT( ( tail ), ( ( head ) + 1 ), ( size ) )
+
+/** Circular buffer is empty ? */
+#define CIRC_EMPTY( head, tail ) ( head == tail )
+/** Clear circular buffer */
+#define CIRC_CLEAR( head, tail ) do { ( head ) = 0; ( tail ) = 0; } while( 0 )
+
+/** Increment head or tail */
+static __inline void circ_inc32( int32_t *lHeadOrTail, uint32_t ulSize )
+{
+ ( *lHeadOrTail ) ++;
+ if( ( *lHeadOrTail ) >= ( int32_t )ulSize )
+ {
+ ( *lHeadOrTail ) = 0;
+ }
+}
+
+/**
+ * \brief Wait PHY operation to be completed.
+ *
+ * \param p_gmac HW controller address.
+ * \param ul_retry The retry times, 0 to wait forever until completeness.
+ *
+ * Return GMAC_OK if the operation is completed successfully.
+ */
+static uint8_t gmac_wait_phy(Gmac* p_gmac, const uint32_t ul_retry)
+{
+ volatile uint32_t ul_retry_count = 0;
+ const uint32_t xPHYPollDelay = pdMS_TO_TICKS( 1ul );
+
+ while (!gmac_is_phy_idle(p_gmac)) {
+ if (ul_retry == 0) {
+ continue;
+ }
+
+ ul_retry_count++;
+
+ if (ul_retry_count >= ul_retry) {
+ return GMAC_TIMEOUT;
+ }
+
+ /* Block the task to allow other tasks to execute while the PHY
+ is not connected. */
+ vTaskDelay( xPHYPollDelay );
+ }
+ return GMAC_OK;
+}
+
+/**
+ * \brief Disable transfer, reset registers and descriptor lists.
+ *
+ * \param p_dev Pointer to GMAC driver instance.
+ *
+ */
+static void gmac_reset_tx_mem(gmac_device_t* p_dev)
+{
+ Gmac *p_hw = p_dev->p_hw;
+ uint8_t *p_tx_buff = p_dev->p_tx_buffer;
+ gmac_tx_descriptor_t *p_td = p_dev->p_tx_dscr;
+
+ uint32_t ul_index;
+ uint32_t ul_address;
+
+ /* Disable TX */
+ gmac_enable_transmit(p_hw, 0);
+
+ /* Set up the TX descriptors */
+ CIRC_CLEAR(p_dev->l_tx_head, p_dev->l_tx_tail);
+ for( ul_index = 0; ul_index < p_dev->ul_tx_list_size; ul_index++ )
+ {
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ ul_address = (uint32_t) 0u;
+ }
+ #else
+ {
+ ul_address = (uint32_t) (&(p_tx_buff[ul_index * GMAC_TX_UNITSIZE]));
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+ p_td[ul_index].addr = ul_address;
+ p_td[ul_index].status.val = GMAC_TXD_USED;
+ }
+ p_td[p_dev->ul_tx_list_size - 1].status.val =
+ GMAC_TXD_USED | GMAC_TXD_WRAP;
+
+ /* Set transmit buffer queue */
+ gmac_set_tx_queue(p_hw, (uint32_t) p_td);
+}
+
+/**
+ * \brief Disable receiver, reset registers and descriptor list.
+ *
+ * \param p_drv Pointer to GMAC Driver instance.
+ */
+static void gmac_reset_rx_mem(gmac_device_t* p_dev)
+{
+ Gmac *p_hw = p_dev->p_hw;
+ uint8_t *p_rx_buff = p_dev->p_rx_buffer;
+ gmac_rx_descriptor_t *pRd = p_dev->p_rx_dscr;
+
+ uint32_t ul_index;
+ uint32_t ul_address;
+
+ /* Disable RX */
+ gmac_enable_receive(p_hw, 0);
+
+ /* Set up the RX descriptors */
+ p_dev->ul_rx_idx = 0;
+ for( ul_index = 0; ul_index < p_dev->ul_rx_list_size; ul_index++ )
+ {
+ ul_address = (uint32_t) (&(p_rx_buff[ul_index * GMAC_RX_UNITSIZE]));
+ pRd[ul_index].addr.val = ul_address & GMAC_RXD_ADDR_MASK;
+ pRd[ul_index].status.val = 0;
+ }
+ pRd[p_dev->ul_rx_list_size - 1].addr.val |= GMAC_RXD_WRAP;
+
+ /* Set receive buffer queue */
+ gmac_set_rx_queue(p_hw, (uint32_t) pRd);
+}
+
+
+/**
+ * \brief Initialize the allocated buffer lists for GMAC driver to transfer data.
+ * Must be invoked after gmac_dev_init() but before RX/TX starts.
+ *
+ * \note If input address is not 8-byte aligned, the address is automatically
+ * adjusted and the list size is reduced by one.
+ *
+ * \param p_gmac Pointer to GMAC instance.
+ * \param p_gmac_dev Pointer to GMAC device instance.
+ * \param p_dev_mm Pointer to the GMAC memory management control block.
+ * \param p_tx_cb Pointer to allocated TX callback list.
+ *
+ * \return GMAC_OK or GMAC_PARAM.
+ */
+static uint8_t gmac_init_mem(Gmac* p_gmac, gmac_device_t* p_gmac_dev,
+ gmac_dev_mem_t* p_dev_mm
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ , gmac_dev_tx_cb_t* p_tx_cb
+#endif
+ )
+{
+ if (p_dev_mm->us_rx_size <= 1 || p_dev_mm->us_tx_size <= 1
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ || p_tx_cb == NULL
+#endif
+ ) {
+ return GMAC_PARAM;
+ }
+
+ /* Assign RX buffers */
+ if (((uint32_t) p_dev_mm->p_rx_buffer & 0x7)
+ || ((uint32_t) p_dev_mm->p_rx_dscr & 0x7)) {
+ p_dev_mm->us_rx_size--;
+ }
+ p_gmac_dev->p_rx_buffer =
+ (uint8_t *) ((uint32_t) p_dev_mm->p_rx_buffer & 0xFFFFFFF8);
+ p_gmac_dev->p_rx_dscr =
+ (gmac_rx_descriptor_t *) ((uint32_t) p_dev_mm->p_rx_dscr
+ & 0xFFFFFFF8);
+ p_gmac_dev->ul_rx_list_size = p_dev_mm->us_rx_size;
+
+ /* Assign TX buffers */
+ if (((uint32_t) p_dev_mm->p_tx_buffer & 0x7)
+ || ((uint32_t) p_dev_mm->p_tx_dscr & 0x7)) {
+ p_dev_mm->us_tx_size--;
+ }
+ p_gmac_dev->p_tx_buffer =
+ (uint8_t *) ((uint32_t) p_dev_mm->p_tx_buffer & 0xFFFFFFF8);
+ p_gmac_dev->p_tx_dscr =
+ (gmac_tx_descriptor_t *) ((uint32_t) p_dev_mm->p_tx_dscr
+ & 0xFFFFFFF8);
+ p_gmac_dev->ul_tx_list_size = p_dev_mm->us_tx_size;
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ p_gmac_dev->func_tx_cb_list = p_tx_cb;
+#endif
+ /* Reset TX & RX */
+ gmac_reset_rx_mem(p_gmac_dev);
+ gmac_reset_tx_mem(p_gmac_dev);
+
+ /* Enable Rx and Tx, plus the statistics register */
+ gmac_enable_transmit(p_gmac, true);
+ gmac_enable_receive(p_gmac, true);
+ gmac_enable_statistics_write(p_gmac, true);
+
+ /* Set up the interrupts for transmission and errors */
+ gmac_enable_interrupt(p_gmac,
+ GMAC_IER_RXUBR | /* Enable receive used bit read interrupt. */
+ GMAC_IER_TUR | /* Enable transmit underrun interrupt. */
+ GMAC_IER_RLEX | /* Enable retry limit exceeded interrupt. */
+ GMAC_IER_TFC | /* Enable transmit buffers exhausted in mid-frame interrupt. */
+ GMAC_IER_TCOMP | /* Enable transmit complete interrupt. */
+ GMAC_IER_ROVR | /* Enable receive overrun interrupt. */
+ GMAC_IER_HRESP | /* Enable Hresp not OK interrupt. */
+ GMAC_IER_PFNZ | /* Enable pause frame received interrupt. */
+ GMAC_IER_PTZ); /* Enable pause time zero interrupt. */
+
+ return GMAC_OK;
+}
+
+/**
+ * \brief Read the PHY register.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_address PHY address.
+ * \param uc_address Register address.
+ * \param p_value Pointer to a 32-bit location to store read data.
+ *
+ * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
+ */
+uint8_t gmac_phy_read(Gmac* p_gmac, uint8_t uc_phy_address, uint8_t uc_address,
+ uint32_t* p_value)
+{
+ gmac_maintain_phy(p_gmac, uc_phy_address, uc_address, 1, 0);
+
+ if (gmac_wait_phy(p_gmac, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT) {
+ return GMAC_TIMEOUT;
+ }
+ *p_value = gmac_get_phy_data(p_gmac);
+ return GMAC_OK;
+}
+
+/**
+ * \brief Write the PHY register.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_address PHY Address.
+ * \param uc_address Register Address.
+ * \param ul_value Data to write, actually 16-bit data.
+ *
+ * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
+ */
+uint8_t gmac_phy_write(Gmac* p_gmac, uint8_t uc_phy_address,
+ uint8_t uc_address, uint32_t ul_value)
+{
+ gmac_maintain_phy(p_gmac, uc_phy_address, uc_address, 0, ul_value);
+
+ if (gmac_wait_phy(p_gmac, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT) {
+ return GMAC_TIMEOUT;
+ }
+ return GMAC_OK;
+}
+
+/**
+ * \brief Initialize the GMAC driver.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param p_gmac_dev Pointer to the GMAC device instance.
+ * \param p_opt GMAC configure options.
+ */
+void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev,
+ gmac_options_t* p_opt)
+{
+ gmac_dev_mem_t gmac_dev_mm;
+
+ /* Disable TX & RX and more */
+ gmac_network_control(p_gmac, 0);
+ gmac_disable_interrupt(p_gmac, ~0u);
+
+
+ gmac_clear_statistics(p_gmac);
+
+ /* Clear all status bits in the receive status register. */
+ gmac_clear_rx_status(p_gmac, GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA);
+
+ /* Clear all status bits in the transmit status register */
+ gmac_clear_tx_status(p_gmac, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE
+ | GMAC_TSR_TFC | GMAC_TSR_TXCOMP | GMAC_TSR_UND);
+
+ /* Clear interrupts */
+ gmac_get_interrupt_status(p_gmac);
+#if !defined(ETHERNET_CONF_DATA_OFFSET)
+ /* Receive Buffer Offset
+ * Indicates the number of bytes by which the received data
+ * is offset from the start of the receive buffer
+ * which can be handy for alignment reasons */
+ /* Note: FreeRTOS+TCP wants to have this offset set to 2 bytes */
+ #error ETHERNET_CONF_DATA_OFFSET not defined, assuming 0
+#endif
+ /* Enable the copy of data into the buffers
+ ignore broadcasts, and not copy FCS. */
+
+ gmac_set_configure(p_gmac,
+ ( gmac_get_configure(p_gmac) & ~GMAC_NCFGR_RXBUFO_Msk ) |
+ GMAC_NCFGR_RFCS | /* Remove FCS, frame check sequence (last 4 bytes) */
+ GMAC_NCFGR_PEN | /* Pause Enable */
+ GMAC_NCFGR_RXBUFO( ETHERNET_CONF_DATA_OFFSET ) |
+ GMAC_RXD_RXCOEN );
+
+ /*
+ * GMAC_DCFGR_TXCOEN: (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable.
+ * Note: tha SAM4E does have RX checksum offloading
+ * but TX checksum offloading has NOT been implemented.
+ * http://community.atmel.com/forum/sam4e-gmac-transmit-checksum-offload-enablesolved
+ */
+
+ gmac_set_dma(p_gmac,
+ gmac_get_dma(p_gmac) | GMAC_DCFGR_TXCOEN );
+
+ gmac_enable_copy_all(p_gmac, p_opt->uc_copy_all_frame);
+ gmac_disable_broadcast(p_gmac, p_opt->uc_no_boardcast);
+
+ /* Fill in GMAC device memory management */
+ gmac_dev_mm.p_rx_buffer = gs_uc_rx_buffer;
+ gmac_dev_mm.p_rx_dscr = gs_rx_desc;
+ gmac_dev_mm.us_rx_size = GMAC_RX_BUFFERS;
+
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ gmac_dev_mm.p_tx_buffer = NULL;
+ }
+ #else
+ {
+ gmac_dev_mm.p_tx_buffer = gs_uc_tx_buffer;
+ }
+ #endif
+ gmac_dev_mm.p_tx_dscr = gs_tx_desc;
+ gmac_dev_mm.us_tx_size = GMAC_TX_BUFFERS;
+
+ gmac_init_mem(p_gmac, p_gmac_dev, &gmac_dev_mm
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ , gs_tx_callback
+#endif
+ );
+
+ gmac_set_address(p_gmac, 0, p_opt->uc_mac_addr);
+}
+
+/**
+ * \brief Frames can be read from the GMAC in multiple sections.
+ *
+ * Returns > 0 if a complete frame is available
+ * It also it cleans up incomplete older frames
+ */
+
+static uint32_t gmac_dev_poll(gmac_device_t* p_gmac_dev)
+{
+ uint32_t ulReturn = 0;
+ int32_t ulIndex = p_gmac_dev->ul_rx_idx;
+ gmac_rx_descriptor_t *pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];
+
+ /* Discard any incomplete frames */
+ while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) &&
+ (pxHead->status.val & GMAC_RXD_SOF) == 0) {
+ pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);
+ circ_inc32 (&ulIndex, p_gmac_dev->ul_rx_list_size);
+ pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];
+ p_gmac_dev->ul_rx_idx = ulIndex;
+ #if( GMAC_STATS != 0 )
+ {
+ gmacStats.incompCount++;
+ }
+ #endif
+ }
+
+ while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) != 0) {
+ if ((pxHead->status.val & GMAC_RXD_EOF) != 0) {
+ /* Here a complete frame has been seen with SOF and EOF */
+ ulReturn = pxHead->status.bm.len;
+ break;
+ }
+ circ_inc32 (&ulIndex, p_gmac_dev->ul_rx_list_size);
+ pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];
+ if ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) == 0) {
+ /* CPU is not the owner (yet) */
+ break;
+ }
+ if ((pxHead->status.val & GMAC_RXD_SOF) != 0) {
+ /* Strange, we found a new Start Of Frame
+ * discard previous segments */
+ int32_t ulPrev = p_gmac_dev->ul_rx_idx;
+ pxHead = &p_gmac_dev->p_rx_dscr[ulPrev];
+ do {
+ pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);
+ circ_inc32 (&ulPrev, p_gmac_dev->ul_rx_list_size);
+ pxHead = &p_gmac_dev->p_rx_dscr[ulPrev];
+ #if( GMAC_STATS != 0 )
+ {
+ gmacStats.truncCount++;
+ }
+ #endif
+ } while (ulPrev != ulIndex);
+ p_gmac_dev->ul_rx_idx = ulIndex;
+ }
+ }
+ return ulReturn;
+}
+
+/**
+ * \brief Frames can be read from the GMAC in multiple sections.
+ * Read ul_frame_size bytes from the GMAC receive buffers to pcTo.
+ * p_rcv_size is the size of the entire frame. Generally gmac_read
+ * will be repeatedly called until the sum of all the ul_frame_size equals
+ * the value of p_rcv_size.
+ *
+ * \param p_gmac_dev Pointer to the GMAC device instance.
+ * \param p_frame Address of the frame buffer.
+ * \param ul_frame_size Length of the frame.
+ * \param p_rcv_size Received frame size.
+ *
+ * \return GMAC_OK if receiving frame successfully, otherwise failed.
+ */
+uint32_t gmac_dev_read(gmac_device_t* p_gmac_dev, uint8_t* p_frame,
+ uint32_t ul_frame_size, uint32_t* p_rcv_size)
+{
+ int32_t nextIdx; /* A copy of the Rx-index 'ul_rx_idx' */
+ int32_t bytesLeft = gmac_dev_poll (p_gmac_dev);
+ gmac_rx_descriptor_t *pxHead;
+
+ if (bytesLeft == 0 )
+ {
+ return GMAC_RX_NULL;
+ }
+
+ /* gmac_dev_poll has confirmed that there is a complete frame at
+ * the current position 'ul_rx_idx'
+ */
+ nextIdx = p_gmac_dev->ul_rx_idx;
+
+ /* Read +2 bytes because buffers are aligned at -2 bytes */
+ bytesLeft = min( bytesLeft + 2, ( int32_t )ul_frame_size );
+
+ /* The frame will be copied in 1 or 2 memcpy's */
+ if( ( p_frame != NULL ) && ( bytesLeft != 0 ) )
+ {
+ const uint8_t *source;
+ int32_t left;
+ int32_t toCopy;
+
+ source = p_gmac_dev->p_rx_buffer + nextIdx * GMAC_RX_UNITSIZE;
+ left = bytesLeft;
+ toCopy = ( p_gmac_dev->ul_rx_list_size - nextIdx ) * GMAC_RX_UNITSIZE;
+ if(toCopy > left )
+ {
+ toCopy = left;
+ }
+ memcpy (p_frame, source, toCopy);
+ left -= toCopy;
+
+ if( left != 0ul )
+ {
+ memcpy (p_frame + toCopy, (void*)p_gmac_dev->p_rx_buffer, left);
+ }
+ }
+
+ do
+ {
+ pxHead = &p_gmac_dev->p_rx_dscr[nextIdx];
+ pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);
+ circ_inc32 (&nextIdx, p_gmac_dev->ul_rx_list_size);
+ } while ((pxHead->status.val & GMAC_RXD_EOF) == 0);
+
+ p_gmac_dev->ul_rx_idx = nextIdx;
+
+ *p_rcv_size = bytesLeft;
+
+ return GMAC_OK;
+}
+
+
+extern void vGMACGenerateChecksum( uint8_t *apBuffer );
+
+/**
+ * \brief Send ulLength bytes from pcFrom. This copies the buffer to one of the
+ * GMAC Tx buffers, and then indicates to the GMAC that the buffer is ready.
+ * If lEndOfFrame is true then the data being copied is the end of the frame
+ * and the frame can be transmitted.
+ *
+ * \param p_gmac_dev Pointer to the GMAC device instance.
+ * \param p_buffer Pointer to the data buffer.
+ * \param ul_size Length of the frame.
+ * \param func_tx_cb Transmit callback function.
+ *
+ * \return Length sent.
+ */
+uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer,
+ uint32_t ul_size, gmac_dev_tx_cb_t func_tx_cb)
+{
+
+ volatile gmac_tx_descriptor_t *p_tx_td;
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ volatile gmac_dev_tx_cb_t *p_func_tx_cb;
+#endif
+
+ Gmac *p_hw = p_gmac_dev->p_hw;
+
+#if( GMAC_USES_TX_CALLBACK == 0 )
+ ( void )func_tx_cb;
+#endif
+
+ /* Check parameter */
+ if (ul_size > GMAC_TX_UNITSIZE) {
+ return GMAC_PARAM;
+ }
+
+ /* Pointers to the current transmit descriptor */
+ p_tx_td = &p_gmac_dev->p_tx_dscr[p_gmac_dev->l_tx_head];
+
+ /* If no free TxTd, buffer can't be sent, schedule the wakeup callback */
+// if (CIRC_SPACE(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
+// p_gmac_dev->ul_tx_list_size) == 0)
+ {
+ if ((p_tx_td->status.val & GMAC_TXD_USED) == 0)
+ return GMAC_TX_BUSY;
+ }
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ /* Pointers to the current Tx callback */
+ p_func_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_head];
+#endif
+
+ /* Set up/copy data to transmission buffer */
+ if (p_buffer && ul_size) {
+ /* Driver manages the ring buffer */
+ /* Calculating the checksum here is faster than calculating it from the GMAC buffer
+ * because withing p_buffer, it is well aligned */
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* Zero-copy... */
+ p_tx_td->addr = ( uint32_t ) p_buffer;
+ }
+ #else
+ {
+ /* Or memcopy... */
+ memcpy((void *)p_tx_td->addr, p_buffer, ul_size);
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+ vGMACGenerateChecksum( ( uint8_t * ) p_tx_td->addr );
+ }
+
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ /* Tx callback */
+ *p_func_tx_cb = func_tx_cb;
+#endif
+
+ /* Update transmit descriptor status */
+
+ /* The buffer size defined is the length of ethernet frame,
+ so it's always the last buffer of the frame. */
+ if( p_gmac_dev->l_tx_head == ( int32_t )( p_gmac_dev->ul_tx_list_size - 1 ) )
+ {
+ /* No need to 'and' with GMAC_TXD_LEN_MASK because ul_size has been checked */
+ p_tx_td->status.val =
+ ul_size | GMAC_TXD_LAST | GMAC_TXD_WRAP;
+ } else {
+ p_tx_td->status.val =
+ ul_size | GMAC_TXD_LAST;
+ }
+
+ circ_inc32( &p_gmac_dev->l_tx_head, p_gmac_dev->ul_tx_list_size );
+
+ /* Now start to transmit if it is still not done */
+ gmac_start_transmission(p_hw);
+
+ return GMAC_OK;
+}
+
+/**
+ * \brief Get current load of transmit.
+ *
+ * \param p_gmac_dev Pointer to the GMAC device instance.
+ *
+ * \return Current load of transmit.
+ */
+#if( GMAC_USES_TX_CALLBACK != 0 )
+/* Without defining GMAC_USES_TX_CALLBACK, l_tx_tail won't be updated */
+uint32_t gmac_dev_get_tx_load(gmac_device_t* p_gmac_dev)
+{
+ uint16_t us_head = p_gmac_dev->l_tx_head;
+ uint16_t us_tail = p_gmac_dev->l_tx_tail;
+ return CIRC_CNT(us_head, us_tail, p_gmac_dev->ul_tx_list_size);
+}
+#endif
+
+/**
+ * \brief Register/Clear RX callback. Callback will be invoked after the next received
+ * frame.
+ *
+ * When gmac_dev_read() returns GMAC_RX_NULL, the application task calls
+ * gmac_dev_set_rx_callback() to register func_rx_cb() callback and enters suspend state.
+ * The callback is in charge to resume the task once a new frame has been
+ * received. The next time gmac_dev_read() is called, it will be successful.
+ *
+ * This function is usually invoked from the RX callback itself with NULL
+ * callback, to unregister. Once the callback has resumed the application task,
+ * there is no need to invoke the callback again.
+ *
+ * \param p_gmac_dev Pointer to the GMAC device instance.
+ * \param func_tx_cb Receive callback function.
+ */
+void gmac_dev_set_rx_callback(gmac_device_t* p_gmac_dev,
+ gmac_dev_rx_cb_t func_rx_cb)
+{
+ Gmac *p_hw = p_gmac_dev->p_hw;
+
+ if (func_rx_cb == NULL) {
+ gmac_disable_interrupt(p_hw, GMAC_IDR_RCOMP);
+ p_gmac_dev->func_rx_cb = NULL;
+ } else {
+ p_gmac_dev->func_rx_cb = func_rx_cb;
+ gmac_enable_interrupt(p_hw, GMAC_IER_RCOMP);
+ }
+}
+
+/**
+ * \brief Register/Clear TX wakeup callback.
+ *
+ * When gmac_dev_write() returns GMAC_TX_BUSY (all transmit descriptor busy), the application
+ * task calls gmac_dev_set_tx_wakeup_callback() to register func_wakeup() callback and
+ * enters suspend state. The callback is in charge to resume the task once
+ * several transmit descriptors have been released. The next time gmac_dev_write() will be called,
+ * it shall be successful.
+ *
+ * This function is usually invoked with NULL callback from the TX wakeup
+ * callback itself, to unregister. Once the callback has resumed the
+ * application task, there is no need to invoke the callback again.
+ *
+ * \param p_gmac_dev Pointer to GMAC device instance.
+ * \param func_wakeup Pointer to wakeup callback function.
+ * \param uc_threshold Number of free transmit descriptor before wakeup callback invoked.
+ *
+ * \return GMAC_OK, GMAC_PARAM on parameter error.
+ */
+#if( GMAC_USES_WAKEUP_CALLBACK )
+uint8_t gmac_dev_set_tx_wakeup_callback(gmac_device_t* p_gmac_dev,
+ gmac_dev_wakeup_cb_t func_wakeup_cb, uint8_t uc_threshold)
+{
+ if (func_wakeup_cb == NULL) {
+ p_gmac_dev->func_wakeup_cb = NULL;
+ } else {
+ if (uc_threshold <= p_gmac_dev->ul_tx_list_size) {
+ p_gmac_dev->func_wakeup_cb = func_wakeup_cb;
+ p_gmac_dev->uc_wakeup_threshold = uc_threshold;
+ } else {
+ return GMAC_PARAM;
+ }
+ }
+
+ return GMAC_OK;
+}
+#endif /* GMAC_USES_WAKEUP_CALLBACK */
+
+/**
+ * \brief Reset TX & RX queue & statistics.
+ *
+ * \param p_gmac_dev Pointer to GMAC device instance.
+ */
+void gmac_dev_reset(gmac_device_t* p_gmac_dev)
+{
+ Gmac *p_hw = p_gmac_dev->p_hw;
+
+ gmac_reset_rx_mem(p_gmac_dev);
+ gmac_reset_tx_mem(p_gmac_dev);
+ gmac_network_control(p_hw, GMAC_NCR_TXEN | GMAC_NCR_RXEN
+ | GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);
+}
+
+void gmac_dev_halt(Gmac* p_gmac);
+
+void gmac_dev_halt(Gmac* p_gmac)
+{
+ gmac_network_control(p_gmac, GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);
+ gmac_disable_interrupt(p_gmac, ~0u);
+}
+
+
+/**
+ * \brief GMAC Interrupt handler.
+ *
+ * \param p_gmac_dev Pointer to GMAC device instance.
+ */
+
+#if( GMAC_STATS != 0 )
+ extern int logPrintf( const char *pcFormat, ... );
+
+ void gmac_show_irq_counts ()
+ {
+ int index;
+ for (index = 0; index < ARRAY_SIZE(intPairs); index++) {
+ if (gmacStats.intStatus[intPairs[index].index]) {
+ logPrintf("%s : %6u\n", intPairs[index].name, gmacStats.intStatus[intPairs[index].index]);
+ }
+ }
+ }
+#endif
+
+void gmac_handler(gmac_device_t* p_gmac_dev)
+{
+ Gmac *p_hw = p_gmac_dev->p_hw;
+
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ gmac_tx_descriptor_t *p_tx_td;
+ gmac_dev_tx_cb_t *p_tx_cb = NULL;
+ uint32_t ul_tx_status_flag;
+#endif
+#if( GMAC_STATS != 0 )
+ int index;
+#endif
+
+ /* volatile */ uint32_t ul_isr;
+ /* volatile */ uint32_t ul_rsr;
+ /* volatile */ uint32_t ul_tsr;
+
+ ul_isr = gmac_get_interrupt_status(p_hw);
+ ul_rsr = gmac_get_rx_status(p_hw);
+ ul_tsr = gmac_get_tx_status(p_hw);
+
+/* Why clear bits that are ignored anyway ? */
+/* ul_isr &= ~(gmac_get_interrupt_mask(p_hw) | 0xF8030300); */
+ #if( GMAC_STATS != 0 )
+ {
+ for (index = 0; index < ARRAY_SIZE(intPairs); index++) {
+ if (ul_isr & intPairs[index].mask)
+ gmacStats.intStatus[intPairs[index].index]++;
+ }
+ }
+ #endif /* GMAC_STATS != 0 */
+
+ /* RX packet */
+ if ((ul_isr & GMAC_ISR_RCOMP) || (ul_rsr & (GMAC_RSR_REC|GMAC_RSR_RXOVR|GMAC_RSR_BNA))) {
+ /* Clear status */
+ gmac_clear_rx_status(p_hw, ul_rsr);
+
+ if (ul_isr & GMAC_ISR_RCOMP)
+ ul_rsr |= GMAC_RSR_REC;
+ /* Invoke callbacks which can be useful to wake op a task */
+ if (p_gmac_dev->func_rx_cb) {
+ p_gmac_dev->func_rx_cb(ul_rsr);
+ }
+ }
+
+ /* TX packet */
+ if ((ul_isr & GMAC_ISR_TCOMP) || (ul_tsr & (GMAC_TSR_TXCOMP|GMAC_TSR_COL|GMAC_TSR_RLE|GMAC_TSR_UND))) {
+
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ ul_tx_status_flag = GMAC_TSR_TXCOMP;
+#endif
+ /* A frame transmitted */
+
+ /* Check RLE */
+ if (ul_tsr & GMAC_TSR_RLE) {
+ /* Status RLE & Number of discarded buffers */
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ ul_tx_status_flag = GMAC_TSR_RLE | CIRC_CNT(p_gmac_dev->l_tx_head,
+ p_gmac_dev->l_tx_tail, p_gmac_dev->ul_tx_list_size);
+ p_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_tail];
+#endif
+ gmac_reset_tx_mem(p_gmac_dev);
+ gmac_enable_transmit(p_hw, 1);
+ }
+ /* Clear status */
+ gmac_clear_tx_status(p_hw, ul_tsr);
+
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ if (!CIRC_EMPTY(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail)) {
+ /* Check the buffers */
+ do {
+ p_tx_td = &p_gmac_dev->p_tx_dscr[p_gmac_dev->l_tx_tail];
+ p_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_tail];
+ /* Any error? Exit if buffer has not been sent yet */
+ if ((p_tx_td->status.val & GMAC_TXD_USED) == 0) {
+ break;
+ }
+
+ /* Notify upper layer that a packet has been sent */
+ if (*p_tx_cb) {
+ (*p_tx_cb) (ul_tx_status_flag, (void*)p_tx_td->addr);
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ p_tx_td->addr = 0ul;
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+ }
+
+ circ_inc32(&p_gmac_dev->l_tx_tail, p_gmac_dev->ul_tx_list_size);
+ } while (CIRC_CNT(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
+ p_gmac_dev->ul_tx_list_size));
+ }
+
+ if (ul_tsr & GMAC_TSR_RLE) {
+ /* Notify upper layer RLE */
+ if (*p_tx_cb) {
+ (*p_tx_cb) (ul_tx_status_flag, NULL);
+ }
+ }
+#endif /* GMAC_USES_TX_CALLBACK */
+
+#if( GMAC_USES_WAKEUP_CALLBACK )
+ /* If a wakeup has been scheduled, notify upper layer that it can
+ send other packets, and the sending will be successful. */
+ if ((CIRC_SPACE(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
+ p_gmac_dev->ul_tx_list_size) >= p_gmac_dev->uc_wakeup_threshold)
+ && p_gmac_dev->func_wakeup_cb) {
+ p_gmac_dev->func_wakeup_cb();
+ }
+#endif
+ }
+}
+
+//@}
+
+/// @cond 0
+/**INDENT-OFF**/
+#ifdef __cplusplus
+}
+#endif
+/**INDENT-ON**/
+/// @endcond
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.h
new file mode 100644
index 000000000..fca3ece33
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.h
@@ -0,0 +1,1346 @@
+ /**
+ * \file
+ *
+ * \brief GMAC (Ethernet MAC) driver for SAM.
+ *
+ * Copyright (c) 2013 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#ifndef GMAC_H_INCLUDED
+#define GMAC_H_INCLUDED
+
+#include "compiler.h"
+
+/// @cond 0
+/**INDENT-OFF**/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**INDENT-ON**/
+/// @endcond
+
+/** The buffer addresses written into the descriptors must be aligned, so the
+ last few bits are zero. These bits have special meaning for the GMAC
+ peripheral and cannot be used as part of the address. */
+#define GMAC_RXD_ADDR_MASK 0xFFFFFFFC
+#define GMAC_RXD_WRAP (1ul << 1) /**< Wrap bit */
+#define GMAC_RXD_OWNERSHIP (1ul << 0) /**< Ownership bit */
+
+#define GMAC_RXD_BROADCAST (1ul << 31) /**< Broadcast detected */
+#define GMAC_RXD_MULTIHASH (1ul << 30) /**< Multicast hash match */
+#define GMAC_RXD_UNIHASH (1ul << 29) /**< Unicast hash match */
+#define GMAC_RXD_ADDR_FOUND (1ul << 27) /**< Specific address match found */
+#define GMAC_RXD_ADDR (3ul << 25) /**< Address match */
+#define GMAC_RXD_RXCOEN (1ul << 24) /**< RXCOEN related function */
+#define GMAC_RXD_TYPE (3ul << 22) /**< Type ID match */
+#define GMAC_RXD_VLAN (1ul << 21) /**< VLAN tag detected */
+#define GMAC_RXD_PRIORITY (1ul << 20) /**< Priority tag detected */
+#define GMAC_RXD_PRIORITY_MASK (3ul << 17) /**< VLAN priority */
+#define GMAC_RXD_CFI (1ul << 16) /**< Concatenation Format Indicator only if bit 21 is set */
+#define GMAC_RXD_EOF (1ul << 15) /**< End of frame */
+#define GMAC_RXD_SOF (1ul << 14) /**< Start of frame */
+#define GMAC_RXD_FCS (1ul << 13) /**< Frame check sequence */
+#define GMAC_RXD_OFFSET_MASK /**< Receive buffer offset */
+#define GMAC_RXD_LEN_MASK (0xFFF) /**< Length of frame including FCS (if selected) */
+#define GMAC_RXD_LENJUMBO_MASK (0x3FFF) /**< Jumbo frame length */
+
+#define GMAC_TXD_USED (1ul << 31) /**< Frame is transmitted */
+#define GMAC_TXD_WRAP (1ul << 30) /**< Last descriptor */
+#define GMAC_TXD_ERROR (1ul << 29) /**< Retry limit exceeded, error */
+#define GMAC_TXD_UNDERRUN (1ul << 28) /**< Transmit underrun */
+#define GMAC_TXD_EXHAUSTED (1ul << 27) /**< Buffer exhausted */
+#define GMAC_TXD_LATE (1ul << 26) /**< Late collision,transmit error */
+#define GMAC_TXD_CHECKSUM_ERROR (7ul << 20) /**< Checksum error */
+#define GMAC_TXD_NOCRC (1ul << 16) /**< No CRC */
+#define GMAC_TXD_LAST (1ul << 15) /**< Last buffer in frame */
+#define GMAC_TXD_LEN_MASK (0x1FFF) /**< Length of buffer */
+
+/** The MAC can support frame lengths up to 1536 bytes */
+#define GMAC_FRAME_LENTGH_MAX 1536
+
+#define GMAC_RX_UNITSIZE 128 /**< Fixed size for RX buffer */
+#define GMAC_TX_UNITSIZE 1518 /**< Size for ETH frame length */
+
+/** GMAC clock speed */
+#define GMAC_MCK_SPEED_240MHZ (240*1000*1000)
+#define GMAC_MCK_SPEED_160MHZ (160*1000*1000)
+#define GMAC_MCK_SPEED_120MHZ (120*1000*1000)
+#define GMAC_MCK_SPEED_80MHZ (80*1000*1000)
+#define GMAC_MCK_SPEED_40MHZ (40*1000*1000)
+#define GMAC_MCK_SPEED_20MHZ (20*1000*1000)
+
+/** GMAC maintain code default value*/
+#define GMAC_MAN_CODE_VALUE (10)
+
+/** GMAC maintain start of frame default value*/
+#define GMAC_MAN_SOF_VALUE (1)
+
+/** GMAC maintain read/write*/
+#define GMAC_MAN_RW_TYPE (2)
+
+/** GMAC maintain read only*/
+#define GMAC_MAN_READ_ONLY (1)
+
+/** GMAC address length */
+#define GMAC_ADDR_LENGTH (6)
+
+
+#define GMAC_DUPLEX_HALF 0
+#define GMAC_DUPLEX_FULL 1
+
+#define GMAC_SPEED_10M 0
+#define GMAC_SPEED_100M 1
+
+/**
+ * \brief Return codes for GMAC APIs.
+ */
+typedef enum {
+ GMAC_OK = 0, /** 0 Operation OK */
+ GMAC_TIMEOUT = 1, /** 1 GMAC operation timeout */
+ GMAC_TX_BUSY, /** 2 TX in progress */
+ GMAC_RX_NULL, /** 3 No data received */
+ GMAC_SIZE_TOO_SMALL, /** 4 Buffer size not enough */
+ GMAC_PARAM, /** 5 Parameter error, TX packet invalid or RX size too small */
+ GMAC_INVALID = 0xFF, /* Invalid */
+} gmac_status_t;
+
+/**
+ * \brief Media Independent Interface (MII) type.
+ */
+typedef enum {
+ GMAC_PHY_MII = 0, /** MII mode */
+ GMAC_PHY_RMII = 1, /** Reduced MII mode */
+ GMAC_PHY_INVALID = 0xFF, /* Invalid mode*/
+} gmac_mii_mode_t;
+
+/** Receive buffer descriptor struct */
+COMPILER_PACK_SET(8)
+typedef struct gmac_rx_descriptor {
+ union gmac_rx_addr {
+ uint32_t val;
+ struct gmac_rx_addr_bm {
+ uint32_t b_ownership:1, /**< User clear, GMAC sets this to 1 once it has successfully written a frame to memory */
+ b_wrap:1, /**< Marks last descriptor in receive buffer */
+ addr_dw:30; /**< Address in number of DW */
+ } bm;
+ } addr; /**< Address, Wrap & Ownership */
+ union gmac_rx_status {
+ uint32_t val;
+ struct gmac_rx_status_bm {
+ uint32_t len:13, /** 0..12 Length of frame including FCS */
+ b_fcs:1, /** 13 Receive buffer offset, bits 13:12 of frame length for jumbo frame */
+ b_sof:1, /** 14 Start of frame */
+ b_eof:1, /** 15 End of frame */
+ b_cfi:1, /** 16 Concatenation Format Indicator */
+ vlan_priority:3, /** 17..19 VLAN priority (if VLAN detected) */
+ b_priority_detected:1, /** 20 Priority tag detected */
+ b_vlan_detected:1, /** 21 VLAN tag detected */
+ b_type_id_match:2, /** 22..23 Type ID match */
+ b_checksumoffload:1, /** 24 Checksum offload specific function */
+ b_addrmatch:2, /** 25..26 Address register match */
+ b_ext_addr_match:1, /** 27 External address match found */
+ reserved:1, /** 28 */
+ b_uni_hash_match:1, /** 29 Unicast hash match */
+ b_multi_hash_match:1, /** 30 Multicast hash match */
+ b_boardcast_detect:1; /** 31 Global broadcast address detected */
+ } bm;
+ } status;
+} gmac_rx_descriptor_t;
+
+/** Transmit buffer descriptor struct */
+COMPILER_PACK_SET(8)
+typedef struct gmac_tx_descriptor {
+ uint32_t addr;
+ union gmac_tx_status {
+ uint32_t val;
+ struct gmac_tx_status_bm {
+ uint32_t len:14, /** 0..13 Length of buffer */
+ reserved:1, /** 14 */
+ b_last_buffer:1, /** 15 Last buffer (in the current frame) */
+ b_no_crc:1, /** 16 No CRC */
+ reserved1:3, /** 17..19 */
+ b_checksumoffload:3, /** 20..22 Transmit checksum generation offload errors */
+ reserved2:3, /** 23..25 */
+ b_lco:1, /** 26 Late collision, transmit error detected */
+ b_exhausted:1, /** 27 Buffer exhausted in mid frame */
+ b_underrun:1, /** 28 Transmit underrun */
+ b_error:1, /** 29 Retry limit exceeded, error detected */
+ b_wrap:1, /** 30 Marks last descriptor in TD list */
+ b_used:1; /** 31 User clear, GMAC sets this to 1 once a frame has been successfully transmitted */
+ } bm;
+ } status;
+} gmac_tx_descriptor_t;
+
+COMPILER_PACK_RESET()
+
+/**
+ * \brief Input parameters when initializing the gmac module mode.
+ */
+typedef struct gmac_options {
+ /* Enable/Disable CopyAllFrame */
+ uint8_t uc_copy_all_frame;
+ /* Enable/Disable NoBroadCast */
+ uint8_t uc_no_boardcast;
+ /* MAC address */
+ uint8_t uc_mac_addr[GMAC_ADDR_LENGTH];
+} gmac_options_t;
+
+/** RX callback */
+typedef void (*gmac_dev_tx_cb_t) (uint32_t ul_status);
+/** Wakeup callback */
+typedef void (*gmac_dev_wakeup_cb_t) (void);
+
+/**
+ * GMAC driver structure.
+ */
+typedef struct gmac_device {
+
+ /** Pointer to HW register base */
+ Gmac *p_hw;
+ /**
+ * Pointer to allocated TX buffer.
+ * Section 3.6 of AMBA 2.0 spec states that burst should not cross
+ * 1K Boundaries.
+ * Receive buffer manager writes are burst of 2 words => 3 lsb bits
+ * of the address shall be set to 0.
+ */
+ uint8_t *p_tx_buffer;
+ /** Pointer to allocated RX buffer */
+ uint8_t *p_rx_buffer;
+ /** Pointer to Rx TDs (must be 8-byte aligned) */
+ gmac_rx_descriptor_t *p_rx_dscr;
+ /** Pointer to Tx TDs (must be 8-byte aligned) */
+ gmac_tx_descriptor_t *p_tx_dscr;
+ /** Optional callback to be invoked once a frame has been received */
+ gmac_dev_tx_cb_t func_rx_cb;
+#if( GMAC_USES_WAKEUP_CALLBACK )
+ /** Optional callback to be invoked once several TDs have been released */
+ gmac_dev_wakeup_cb_t func_wakeup_cb;
+#endif
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ /** Optional callback list to be invoked once TD has been processed */
+ gmac_dev_tx_cb_t *func_tx_cb_list;
+#endif
+ /** RX TD list size */
+ uint32_t ul_rx_list_size;
+ /** RX index for current processing TD */
+ uint32_t ul_rx_idx;
+ /** TX TD list size */
+ uint32_t ul_tx_list_size;
+ /** Circular buffer head pointer by upper layer (buffer to be sent) */
+ int32_t l_tx_head;
+ /** Circular buffer tail pointer incremented by handlers (buffer sent) */
+ int32_t l_tx_tail;
+
+ /** Number of free TD before wakeup callback is invoked */
+ uint32_t uc_wakeup_threshold;
+} gmac_device_t;
+
+/**
+ * \brief Write network control value.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_ncr Network control value.
+ */
+static inline void gmac_network_control(Gmac* p_gmac, uint32_t ul_ncr)
+{
+ p_gmac->GMAC_NCR = ul_ncr;
+}
+
+/**
+ * \brief Get network control value.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+
+static inline uint32_t gmac_get_network_control(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_NCR;
+}
+
+/**
+ * \brief Enable/Disable GMAC receive.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable GMAC receiver, else to enable it.
+ */
+static inline void gmac_enable_receive(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_RXEN;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_RXEN;
+ }
+}
+
+/**
+ * \brief Enable/Disable GMAC transmit.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable GMAC transmit, else to enable it.
+ */
+static inline void gmac_enable_transmit(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_TXEN;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_TXEN;
+ }
+}
+
+/**
+ * \brief Enable/Disable GMAC management.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable GMAC management, else to enable it.
+ */
+static inline void gmac_enable_management(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_MPE;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_MPE;
+ }
+}
+
+/**
+ * \brief Clear all statistics registers.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_clear_statistics(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_CLRSTAT;
+}
+
+/**
+ * \brief Increase all statistics registers.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_increase_statistics(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_INCSTAT;
+}
+
+/**
+ * \brief Enable/Disable statistics registers writing.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the statistics registers writing, else to enable it.
+ */
+static inline void gmac_enable_statistics_write(Gmac* p_gmac,
+ uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_WESTAT;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_WESTAT;
+ }
+}
+
+/**
+ * \brief In half-duplex mode, forces collisions on all received frames.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the back pressure, else to enable it.
+ */
+static inline void gmac_enable_back_pressure(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_BP;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_BP;
+ }
+}
+
+/**
+ * \brief Start transmission.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_start_transmission(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_TSTART;
+}
+
+/**
+ * \brief Halt transmission.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_halt_transmission(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_THALT;
+}
+
+/**
+ * \brief Transmit pause frame.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_tx_pause_frame(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_TXPF;
+}
+
+/**
+ * \brief Transmit zero quantum pause frame.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_tx_pause_zero_quantum_frame(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_TXZQPF;
+}
+
+/**
+ * \brief Read snapshot.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_read_snapshot(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_RDS;
+}
+
+/**
+ * \brief Store receivetime stamp to memory.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to normal operation, else to enable the store.
+ */
+static inline void gmac_store_rx_time_stamp(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_SRTSM;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_SRTSM;
+ }
+}
+
+/**
+ * \brief Enable PFC priority-based pause reception.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 1 to set the reception, 0 to disable.
+ */
+static inline void gmac_enable_pfc_pause_frame(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_ENPBPR;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_ENPBPR;
+ }
+}
+
+/**
+ * \brief Transmit PFC priority-based pause reception.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_transmit_pfc_pause_frame(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_TXPBPF;
+}
+
+/**
+ * \brief Flush next packet.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_flush_next_packet(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_FNP;
+}
+
+/**
+ * \brief Set up network configuration register.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_cfg Network configuration value.
+ */
+static inline void gmac_set_configure(Gmac* p_gmac, uint32_t ul_cfg)
+{
+ p_gmac->GMAC_NCFGR = ul_cfg;
+}
+
+/**
+ * \brief Get network configuration.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Network configuration.
+ */
+static inline uint32_t gmac_get_configure(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_NCFGR;
+}
+
+
+/* Get and set DMA Configuration Register */
+static inline void gmac_set_dma(Gmac* p_gmac, uint32_t ul_cfg)
+{
+ p_gmac->GMAC_DCFGR = ul_cfg;
+}
+
+static inline uint32_t gmac_get_dma(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_DCFGR;
+}
+
+/**
+ * \brief Set speed.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_speed 1 to indicate 100Mbps, 0 to 10Mbps.
+ */
+static inline void gmac_set_speed(Gmac* p_gmac, uint8_t uc_speed)
+{
+ if (uc_speed) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_SPD;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_SPD;
+ }
+}
+
+/**
+ * \brief Enable/Disable Full-Duplex mode.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the Full-Duplex mode, else to enable it.
+ */
+static inline void gmac_enable_full_duplex(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_FD;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_FD;
+ }
+}
+
+/**
+ * \brief Enable/Disable Copy(Receive) All Valid Frames.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable copying all valid frames, else to enable it.
+ */
+static inline void gmac_enable_copy_all(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_CAF;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_CAF;
+ }
+}
+
+/**
+ * \brief Enable/Disable jumbo frames (up to 10240 bytes).
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the jumbo frames, else to enable it.
+ */
+static inline void gmac_enable_jumbo_frames(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_JFRAME;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_JFRAME;
+ }
+}
+
+/**
+ * \brief Disable/Enable broadcast receiving.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 1 to disable the broadcast, else to enable it.
+ */
+static inline void gmac_disable_broadcast(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_NBC;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_NBC;
+ }
+}
+
+/**
+ * \brief Enable/Disable multicast hash.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the multicast hash, else to enable it.
+ */
+static inline void gmac_enable_multicast_hash(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_UNIHEN;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_UNIHEN;
+ }
+}
+
+/**
+ * \brief Enable/Disable big frames (over 1518, up to 1536).
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable big frames else to enable it.
+ */
+static inline void gmac_enable_big_frame(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_MAXFS;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_MAXFS;
+ }
+}
+
+/**
+ * \brief Set MDC clock divider.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_mck GMAC MCK.
+ *
+ * \return GMAC_OK if successfully.
+ */
+static inline uint8_t gmac_set_mdc_clock(Gmac* p_gmac, uint32_t ul_mck)
+{
+ uint32_t ul_clk;
+
+ if (ul_mck > GMAC_MCK_SPEED_240MHZ) {
+ return GMAC_INVALID;
+ } else if (ul_mck > GMAC_MCK_SPEED_160MHZ) {
+ ul_clk = GMAC_NCFGR_CLK_MCK_96;
+ } else if (ul_mck > GMAC_MCK_SPEED_120MHZ) {
+ ul_clk = GMAC_NCFGR_CLK_MCK_64;
+ } else if (ul_mck > GMAC_MCK_SPEED_80MHZ) {
+ ul_clk = GMAC_NCFGR_CLK_MCK_48;
+ } else if (ul_mck > GMAC_MCK_SPEED_40MHZ) {
+ ul_clk = GMAC_NCFGR_CLK_MCK_32;
+ } else if (ul_mck > GMAC_MCK_SPEED_20MHZ) {
+ ul_clk = GMAC_NCFGR_CLK_MCK_16;
+ } else {
+ ul_clk = GMAC_NCFGR_CLK_MCK_8;
+ }
+ ;
+ p_gmac->GMAC_NCFGR = (p_gmac->GMAC_NCFGR & ~GMAC_NCFGR_CLK_Msk) | ul_clk;
+ return GMAC_OK;
+}
+
+/**
+ * \brief Enable/Disable retry test.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the GMAC receiver, else to enable it.
+ */
+static inline void gmac_enable_retry_test(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RTY;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RTY;
+ }
+}
+
+/**
+ * \brief Enable/Disable pause (when a valid pause frame is received).
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable pause frame, else to enable it.
+ */
+static inline void gmac_enable_pause_frame(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_PEN;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_PEN;
+ }
+}
+
+/**
+ * \brief Set receive buffer offset to 0 ~ 3.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_set_rx_buffer_offset(Gmac* p_gmac, uint8_t uc_offset)
+{
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RXBUFO_Msk;
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RXBUFO(uc_offset);
+}
+
+/**
+ * \brief Enable/Disable receive length field checking.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable receive length field checking, else to enable it.
+ */
+static inline void gmac_enable_rx_length_check(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_LFERD;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_LFERD;
+ }
+}
+
+/**
+ * \brief Enable/Disable discarding FCS field of received frames.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable discarding FCS field of received frames, else to enable it.
+ */
+static inline void gmac_enable_discard_fcs(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RFCS;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RFCS;
+ }
+}
+
+
+/**
+ * \brief Enable/Disable frames to be received in half-duplex mode
+ * while transmitting.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the received in half-duplex mode, else to enable it.
+ */
+static inline void gmac_enable_efrhd(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_EFRHD;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_EFRHD;
+ }
+}
+
+/**
+ * \brief Enable/Disable ignore RX FCS.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable ignore RX FCS, else to enable it.
+ */
+static inline void gmac_enable_ignore_rx_fcs(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_IRXFCS;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_IRXFCS;
+ }
+}
+
+/**
+ * \brief Get Network Status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Network status.
+ */
+static inline uint32_t gmac_get_status(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_NSR;
+}
+
+/**
+ * \brief Get MDIO IN pin status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return MDIO IN pin status.
+ */
+static inline uint8_t gmac_get_MDIO(Gmac* p_gmac)
+{
+ return ((p_gmac->GMAC_NSR & GMAC_NSR_MDIO) > 0);
+}
+
+/**
+ * \brief Check if PHY is idle.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return 1 if PHY is idle.
+ */
+static inline uint8_t gmac_is_phy_idle(Gmac* p_gmac)
+{
+ return ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) > 0);
+}
+
+/**
+ * \brief Return transmit status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Transmit status.
+ */
+static inline uint32_t gmac_get_tx_status(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_TSR;
+}
+
+/**
+ * \brief Clear transmit status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_status Transmit status.
+ */
+static inline void gmac_clear_tx_status(Gmac* p_gmac, uint32_t ul_status)
+{
+ p_gmac->GMAC_TSR = ul_status;
+}
+
+/**
+ * \brief Return receive status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline uint32_t gmac_get_rx_status(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_RSR;
+}
+
+/**
+ * \brief Clear receive status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_status Receive status.
+ */
+static inline void gmac_clear_rx_status(Gmac* p_gmac, uint32_t ul_status)
+{
+ p_gmac->GMAC_RSR = ul_status;
+}
+
+/**
+ * \brief Set Rx Queue.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_addr Rx queue address.
+ */
+static inline void gmac_set_rx_queue(Gmac* p_gmac, uint32_t ul_addr)
+{
+ p_gmac->GMAC_RBQB = GMAC_RBQB_ADDR_Msk & ul_addr;
+}
+
+/**
+ * \brief Get Rx Queue Address.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Rx queue address.
+ */
+static inline uint32_t gmac_get_rx_queue(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_RBQB;
+}
+
+/**
+ * \brief Set Tx Queue.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_addr Tx queue address.
+ */
+static inline void gmac_set_tx_queue(Gmac* p_gmac, uint32_t ul_addr)
+{
+ p_gmac->GMAC_TBQB = GMAC_TBQB_ADDR_Msk & ul_addr;
+}
+
+/**
+ * \brief Get Tx Queue.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Rx queue address.
+ */
+static inline uint32_t gmac_get_tx_queue(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_TBQB;
+}
+
+/**
+ * \brief Enable interrupt(s).
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_source Interrupt source(s) to be enabled.
+ */
+static inline void gmac_enable_interrupt(Gmac* p_gmac, uint32_t ul_source)
+{
+ p_gmac->GMAC_IER = ul_source;
+}
+
+/**
+ * \brief Disable interrupt(s).
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_source Interrupt source(s) to be disabled.
+ */
+static inline void gmac_disable_interrupt(Gmac* p_gmac, uint32_t ul_source)
+{
+ p_gmac->GMAC_IDR = ul_source;
+}
+
+/**
+ * \brief Return interrupt status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Interrupt status.
+ */
+static inline uint32_t gmac_get_interrupt_status(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_ISR;
+}
+
+/**
+ * \brief Return interrupt mask.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Interrupt mask.
+ */
+static inline uint32_t gmac_get_interrupt_mask(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_IMR;
+}
+
+/**
+ * \brief Execute PHY maintenance command.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_addr PHY address.
+ * \param uc_reg_addr Register address.
+ * \param uc_rw 1 to Read, 0 to write.
+ * \param us_data Data to be performed, write only.
+ */
+static inline void gmac_maintain_phy(Gmac* p_gmac,
+ uint8_t uc_phy_addr, uint8_t uc_reg_addr, uint8_t uc_rw,
+ uint16_t us_data)
+{
+ /* Wait until bus idle */
+ while ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) == 0);
+ /* Write maintain register */
+ p_gmac->GMAC_MAN = GMAC_MAN_WTN(GMAC_MAN_CODE_VALUE)
+ | GMAC_MAN_CLTTO
+ | GMAC_MAN_PHYA(uc_phy_addr)
+ | GMAC_MAN_REGA(uc_reg_addr)
+ | GMAC_MAN_OP((uc_rw ? GMAC_MAN_RW_TYPE : GMAC_MAN_READ_ONLY))
+ | GMAC_MAN_DATA(us_data);
+}
+
+/**
+ * \brief Get PHY maintenance data returned.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Get PHY data.
+ */
+static inline uint16_t gmac_get_phy_data(Gmac* p_gmac)
+{
+ /* Wait until bus idle */
+ while ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) == 0);
+ /* Return data */
+ return (uint16_t) (p_gmac->GMAC_MAN & GMAC_MAN_DATA_Msk);
+}
+
+/**
+ * \brief Set Hash.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_hash_top Hash top.
+ * \param ul_hash_bottom Hash bottom.
+ */
+static inline void gmac_set_hash(Gmac* p_gmac, uint32_t ul_hash_top,
+ uint32_t ul_hash_bottom)
+{
+ p_gmac->GMAC_HRB = ul_hash_bottom;
+ p_gmac->GMAC_HRT = ul_hash_top;
+}
+
+/**
+ * \brief Set 64 bits Hash.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ull_hash 64 bits hash value.
+ */
+static inline void gmac_set_hash64(Gmac* p_gmac, uint64_t ull_hash)
+{
+ p_gmac->GMAC_HRB = (uint32_t) ull_hash;
+ p_gmac->GMAC_HRT = (uint32_t) (ull_hash >> 32);
+}
+
+/**
+ * \brief Set MAC Address.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_index GMAC specific address register index.
+ * \param p_mac_addr GMAC address.
+ */
+static inline void gmac_set_address(Gmac* p_gmac, uint8_t uc_index,
+ uint8_t* p_mac_addr)
+{
+ p_gmac->GMAC_SA[uc_index].GMAC_SAB = (p_mac_addr[3] << 24)
+ | (p_mac_addr[2] << 16)
+ | (p_mac_addr[1] << 8)
+ | (p_mac_addr[0]);
+ p_gmac->GMAC_SA[uc_index].GMAC_SAT = (p_mac_addr[5] << 8)
+ | (p_mac_addr[4]);
+}
+
+/**
+ * \brief Set MAC Address via 2 dword.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_index GMAC specific address register index.
+ * \param ul_mac_top GMAC top address.
+ * \param ul_mac_bottom GMAC bottom address.
+ */
+static inline void gmac_set_address32(Gmac* p_gmac, uint8_t uc_index,
+ uint32_t ul_mac_top, uint32_t ul_mac_bottom)
+{
+ p_gmac->GMAC_SA[uc_index].GMAC_SAB = ul_mac_bottom;
+ p_gmac->GMAC_SA[uc_index].GMAC_SAT = ul_mac_top;
+}
+
+/**
+ * \brief Set MAC Address via int64.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_index GMAC specific address register index.
+ * \param ull_mac 64-bit GMAC address.
+ */
+static inline void gmac_set_address64(Gmac* p_gmac, uint8_t uc_index,
+ uint64_t ull_mac)
+{
+ p_gmac->GMAC_SA[uc_index].GMAC_SAB = (uint32_t) ull_mac;
+ p_gmac->GMAC_SA[uc_index].GMAC_SAT = (uint32_t) (ull_mac >> 32);
+}
+
+/**
+ * \brief Select media independent interface mode.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param mode Media independent interface mode.
+ */
+static inline void gmac_select_mii_mode(Gmac* p_gmac, gmac_mii_mode_t mode)
+{
+ switch (mode) {
+ case GMAC_PHY_MII:
+ case GMAC_PHY_RMII:
+ p_gmac->GMAC_UR |= GMAC_UR_RMIIMII;
+ break;
+
+ default:
+ p_gmac->GMAC_UR &= ~GMAC_UR_RMIIMII;
+ break;
+ }
+}
+
+uint8_t gmac_phy_read(Gmac* p_gmac, uint8_t uc_phy_address, uint8_t uc_address,
+ uint32_t* p_value);
+uint8_t gmac_phy_write(Gmac* p_gmac, uint8_t uc_phy_address,
+ uint8_t uc_address, uint32_t ul_value);
+void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev,
+ gmac_options_t* p_opt);
+uint32_t gmac_dev_read(gmac_device_t* p_gmac_dev, uint8_t* p_frame,
+ uint32_t ul_frame_size, uint32_t* p_rcv_size);
+uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer,
+ uint32_t ul_size, gmac_dev_tx_cb_t func_tx_cb);
+uint32_t gmac_dev_get_tx_load(gmac_device_t* p_gmac_dev);
+void gmac_dev_set_rx_callback(gmac_device_t* p_gmac_dev,
+ gmac_dev_tx_cb_t func_rx_cb);
+uint8_t gmac_dev_set_tx_wakeup_callback(gmac_device_t* p_gmac_dev,
+ gmac_dev_wakeup_cb_t func_wakeup, uint8_t uc_threshold);
+void gmac_dev_reset(gmac_device_t* p_gmac_dev);
+void gmac_handler(gmac_device_t* p_gmac_dev);
+
+/// @cond 0
+/**INDENT-OFF**/
+#ifdef __cplusplus
+}
+#endif
+/**INDENT-ON**/
+/// @endcond
+
+/**
+ * \page gmac_quickstart Quickstart guide for GMAC driver.
+ *
+ * This is the quickstart guide for the \ref gmac_group "Ethernet MAC",
+ * with step-by-step instructions on how to configure and use the driver in a
+ * selection of use cases.
+ *
+ * The use cases contain several code fragments. The code fragments in the
+ * steps for setup can be copied into a custom initialization function, while
+ * the steps for usage can be copied into, e.g., the main application function.
+ *
+ * \section gmac_basic_use_case Basic use case
+ * In the basic use case, the GMAC driver are configured for:
+ * - PHY component KSZ8051MNL is used
+ * - GMAC uses MII mode
+ * - The number of receive buffer is 16
+ * - The number of transfer buffer is 8
+ * - MAC address is set to 00-04-25-1c-a0-02
+ * - IP address is set to 192.168.0.2
+ * - IP address is set to 192.168.0.2
+ * - Gateway is set to 192.168.0.1
+ * - Network mask is 255.255.255.0
+ * - PHY operation max retry count is 1000000
+ * - GMAC is configured to not support copy all frame and support broadcast
+ * - The data will be read from the ethernet
+ *
+ * \section gmac_basic_use_case_setup Setup steps
+ *
+ * \subsection gmac_basic_use_case_setup_prereq Prerequisites
+ * -# \ref sysclk_group "System Clock Management (sysclock)"
+ * -# \ref pmc_group "Power Management Controller (pmc)"
+ * -# \ref ksz8051mnl_ethernet_phy_group "PHY component (KSZ8051MNL)"
+ *
+ * \subsection gmac_basic_use_case_setup_code Example code
+ * Content of conf_eth.h
+ * \code
+ * #define GMAC_RX_BUFFERS 16
+ * #define GMAC_TX_BUFFERS 8
+ * #define MAC_PHY_RETRY_MAX 1000000
+ * #define ETHERNET_CONF_ETHADDR0 0x00
+ * #define ETHERNET_CONF_ETHADDR0 0x00
+ * #define ETHERNET_CONF_ETHADDR1 0x04
+ * #define ETHERNET_CONF_ETHADDR2 0x25
+ * #define ETHERNET_CONF_ETHADDR3 0x1C
+ * #define ETHERNET_CONF_ETHADDR4 0xA0
+ * #define ETHERNET_CONF_ETHADDR5 0x02
+ * #define ETHERNET_CONF_IPADDR0 192
+ * #define ETHERNET_CONF_IPADDR1 168
+ * #define ETHERNET_CONF_IPADDR2 0
+ * #define ETHERNET_CONF_IPADDR3 2
+ * #define ETHERNET_CONF_GATEWAY_ADDR0 192
+ * #define ETHERNET_CONF_GATEWAY_ADDR1 168
+ * #define ETHERNET_CONF_GATEWAY_ADDR2 0
+ * #define ETHERNET_CONF_GATEWAY_ADDR3 1
+ * #define ETHERNET_CONF_NET_MASK0 255
+ * #define ETHERNET_CONF_NET_MASK1 255
+ * #define ETHERNET_CONF_NET_MASK2 255
+ * #define ETHERNET_CONF_NET_MASK3 0
+ * #define ETH_PHY_MODE ETH_PHY_MODE
+ * \endcode
+ *
+ * A specific gmac device and the receive data buffer must be defined; another ul_frm_size should be defined
+ * to trace the actual size of the data received.
+ * \code
+ * static gmac_device_t gs_gmac_dev;
+ * static volatile uint8_t gs_uc_eth_buffer[GMAC_FRAME_LENTGH_MAX];
+ *
+ * uint32_t ul_frm_size;
+ * \endcode
+ *
+ * Add to application C-file:
+ * \code
+ * void gmac_init(void)
+ * {
+ * sysclk_init();
+ *
+ * board_init();
+ *
+ * pmc_enable_periph_clk(ID_GMAC);
+ *
+ * gmac_option.uc_copy_all_frame = 0;
+ * gmac_option.uc_no_boardcast = 0;
+ * memcpy(gmac_option.uc_mac_addr, gs_uc_mac_address, sizeof(gs_uc_mac_address));
+ * gs_gmac_dev.p_hw = GMAC;
+ *
+ * gmac_dev_init(GMAC, &gs_gmac_dev, &gmac_option);
+ *
+ * NVIC_EnableIRQ(GMAC_IRQn);
+ *
+ * ethernet_phy_init(GMAC, BOARD_GMAC_PHY_ADDR, sysclk_get_cpu_hz());
+ *
+ * ethernet_phy_auto_negotiate(GMAC, BOARD_GMAC_PHY_ADDR);
+ *
+ * ethernet_phy_set_link(GMAC, BOARD_GMAC_PHY_ADDR, 1);
+ * \endcode
+ *
+ * \subsection gmac_basic_use_case_setup_flow Workflow
+ * - Ensure that conf_eth.h is present and contains the
+ * following configuration symbol. This configuration file is used
+ * by the driver and should not be included by the application.
+ * -# Define the receiving buffer size used in the internal GMAC driver.
+ * The buffer size used for RX is GMAC_RX_BUFFERS * 128.
+ * If it was supposed receiving a large number of frame, the
+ * GMAC_RX_BUFFERS should be set higher. E.g., the application wants to accept
+ * a ping echo test of 2048, the GMAC_RX_BUFFERS should be set at least
+ * (2048/128)=16, and as there are additional frames coming, a preferred
+ * number is 24 depending on a normal Ethernet throughput.
+ * - \code
+ * #define GMAC_RX_BUFFERS 16
+ * \endcode
+ * -# Define the transmitting buffer size used in the internal GMAC driver.
+ * The buffer size used for TX is GMAC_TX_BUFFERS * 1518.
+ * - \code
+ * #define GMAC_TX_BUFFERS 8
+ * \endcode
+ * -# Define maximum retry time for a PHY read/write operation.
+ * - \code
+ * #define MAC_PHY_RETRY_MAX 1000000
+ * \endcode
+ * -# Define the MAC address. 00:04:25:1C:A0:02 is the address reserved
+ * for ATMEL, application should always change this address to its' own.
+ * - \code
+ * #define ETHERNET_CONF_ETHADDR0 0x00
+ * #define ETHERNET_CONF_ETHADDR1 0x04
+ * #define ETHERNET_CONF_ETHADDR2 0x25
+ * #define ETHERNET_CONF_ETHADDR3 0x1C
+ * #define ETHERNET_CONF_ETHADDR4 0xA0
+ * #define ETHERNET_CONF_ETHADDR5 0x02
+ * \endcode
+ * -# Define the IP address configration used in the application. When DHCP
+ * is enabled, this configuration is not effected.
+ * - \code
+ * #define ETHERNET_CONF_IPADDR0 192
+ * #define ETHERNET_CONF_IPADDR1 168
+ * #define ETHERNET_CONF_IPADDR2 0
+ * #define ETHERNET_CONF_IPADDR3 2
+ * #define ETHERNET_CONF_GATEWAY_ADDR0 192
+ * #define ETHERNET_CONF_GATEWAY_ADDR1 168
+ * #define ETHERNET_CONF_GATEWAY_ADDR2 0
+ * #define ETHERNET_CONF_GATEWAY_ADDR3 1
+ * #define ETHERNET_CONF_NET_MASK0 255
+ * #define ETHERNET_CONF_NET_MASK1 255
+ * #define ETHERNET_CONF_NET_MASK2 255
+ * #define ETHERNET_CONF_NET_MASK3 0
+ * \endcode
+ * -# Configure the PHY maintainance interface.
+ * - \code
+ * #define ETH_PHY_MODE GMAC_PHY_MII
+ * \endcode
+ * -# Enable the system clock:
+ * - \code sysclk_init(); \endcode
+ * -# Enable PIO configurations for GMAC:
+ * - \code board_init(); \endcode
+ * -# Enable PMC clock for GMAC:
+ * - \code pmc_enable_periph_clk(ID_GMAC); \endcode
+ * -# Set the GMAC options; it's set to copy all frame and support broadcast:
+ * - \code
+ * gmac_option.uc_copy_all_frame = 0;
+ * gmac_option.uc_no_boardcast = 0;
+ * memcpy(gmac_option.uc_mac_addr, gs_uc_mac_address, sizeof(gs_uc_mac_address));
+ * gs_gmac_dev.p_hw = GMAC;
+ * \endcode
+ * -# Initialize GMAC device with the filled option:
+ * - \code
+ * gmac_dev_init(GMAC, &gs_gmac_dev, &gmac_option);
+ * \endcode
+ * -# Enable the interrupt service for GMAC:
+ * - \code
+ * NVIC_EnableIRQ(GMAC_IRQn);
+ * \endcode
+ * -# Initialize the PHY component:
+ * - \code
+ * ethernet_phy_init(GMAC, BOARD_GMAC_PHY_ADDR, sysclk_get_cpu_hz());
+ * \endcode
+ * -# The link will be established based on auto negotiation.
+ * - \code
+ * ethernet_phy_auto_negotiate(GMAC, BOARD_GMAC_PHY_ADDR);
+ * \endcode
+ * -# Establish the ethernet link; the network can be worked from now on:
+ * - \code
+ * ethernet_phy_set_link(GMAC, BOARD_GMAC_PHY_ADDR, 1);
+ * \endcode
+ *
+ * \section gmac_basic_use_case_usage Usage steps
+ * \subsection gmac_basic_use_case_usage_code Example code
+ * Add to, e.g., main loop in application C-file:
+ * \code
+ * gmac_dev_read(&gs_gmac_dev, (uint8_t *) gs_uc_eth_buffer, sizeof(gs_uc_eth_buffer), &ul_frm_size));
+ * \endcode
+ *
+ * \subsection gmac_basic_use_case_usage_flow Workflow
+ * -# Start reading the data from the ethernet:
+ * - \code gmac_dev_read(&gs_gmac_dev, (uint8_t *) gs_uc_eth_buffer, sizeof(gs_uc_eth_buffer), &ul_frm_size)); \endcode
+ */
+
+# define GMAC_STATS 0
+
+#if( GMAC_STATS != 0 )
+
+ /* Here below some code to study the types and
+ frequencies of GMAC interrupts. */
+ #define GMAC_IDX_RXUBR 0
+ #define GMAC_IDX_TUR 1
+ #define GMAC_IDX_RLEX 2
+ #define GMAC_IDX_TFC 3
+ #define GMAC_IDX_RCOMP 4
+ #define GMAC_IDX_TCOMP 5
+ #define GMAC_IDX_ROVR 6
+ #define GMAC_IDX_HRESP 7
+ #define GMAC_IDX_PFNZ 8
+ #define GMAC_IDX_PTZ 9
+
+ struct SGmacStats {
+ unsigned recvCount;
+ unsigned rovrCount;
+ unsigned bnaCount;
+ unsigned sendCount;
+ unsigned sovrCount;
+ unsigned incompCount;
+ unsigned truncCount;
+
+ unsigned intStatus[10];
+ };
+ extern struct SGmacStats gmacStats;
+
+ struct SIntPair {
+ const char *name;
+ unsigned mask;
+ int index;
+ };
+
+ #define MK_PAIR( NAME ) #NAME, GMAC_IER_##NAME, GMAC_IDX_##NAME
+ static const struct SIntPair intPairs[] = {
+ { MK_PAIR( RXUBR ) }, /* Enable receive used bit read interrupt. */
+ { MK_PAIR( TUR ) }, /* Enable transmit underrun interrupt. */
+ { MK_PAIR( RLEX ) }, /* Enable retry limit exceeded interrupt. */
+ { MK_PAIR( TFC ) }, /* Enable transmit buffers exhausted in mid-frame interrupt. */
+ { MK_PAIR( RCOMP ) }, /* Receive complete */
+ { MK_PAIR( TCOMP ) }, /* Enable transmit complete interrupt. */
+ { MK_PAIR( ROVR ) }, /* Enable receive overrun interrupt. */
+ { MK_PAIR( HRESP ) }, /* Enable Hresp not OK interrupt. */
+ { MK_PAIR( PFNZ ) }, /* Enable pause frame received interrupt. */
+ { MK_PAIR( PTZ ) } /* Enable pause time zero interrupt. */
+ };
+
+ void gmac_show_irq_counts ();
+
+#endif
+
+#endif /* GMAC_H_INCLUDED */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/instance/gmac.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/instance/gmac.h
new file mode 100644
index 000000000..24d806d94
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/instance/gmac.h
@@ -0,0 +1,1349 @@
+ /**
+ * \file
+ *
+ * \brief GMAC (Ethernet MAC) driver for SAM.
+ *
+ * Copyright (c) 2013 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#ifndef GMAC_H_INCLUDED
+#define GMAC_H_INCLUDED
+
+#include "compiler.h"
+#include "component/gmac.h"
+
+/// @cond 0
+/**INDENT-OFF**/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**INDENT-ON**/
+/// @endcond
+
+/** The buffer addresses written into the descriptors must be aligned, so the
+ last few bits are zero. These bits have special meaning for the GMAC
+ peripheral and cannot be used as part of the address. */
+#define GMAC_RXD_ADDR_MASK 0xFFFFFFFC
+#define GMAC_RXD_WRAP (1ul << 1) /**< Wrap bit */
+#define GMAC_RXD_OWNERSHIP (1ul << 0) /**< Ownership bit */
+
+#define GMAC_RXD_BROADCAST (1ul << 31) /**< Broadcast detected */
+#define GMAC_RXD_MULTIHASH (1ul << 30) /**< Multicast hash match */
+#define GMAC_RXD_UNIHASH (1ul << 29) /**< Unicast hash match */
+#define GMAC_RXD_ADDR_FOUND (1ul << 27) /**< Specific address match found */
+#define GMAC_RXD_ADDR (3ul << 25) /**< Address match */
+#define GMAC_RXD_RXCOEN (1ul << 24) /**< RXCOEN related function */
+#define GMAC_RXD_TYPE (3ul << 22) /**< Type ID match */
+#define GMAC_RXD_VLAN (1ul << 21) /**< VLAN tag detected */
+#define GMAC_RXD_PRIORITY (1ul << 20) /**< Priority tag detected */
+#define GMAC_RXD_PRIORITY_MASK (3ul << 17) /**< VLAN priority */
+#define GMAC_RXD_CFI (1ul << 16) /**< Concatenation Format Indicator only if bit 21 is set */
+#define GMAC_RXD_EOF (1ul << 15) /**< End of frame */
+#define GMAC_RXD_SOF (1ul << 14) /**< Start of frame */
+#define GMAC_RXD_FCS (1ul << 13) /**< Frame check sequence */
+#define GMAC_RXD_OFFSET_MASK /**< Receive buffer offset */
+#define GMAC_RXD_LEN_MASK (0xFFF) /**< Length of frame including FCS (if selected) */
+#define GMAC_RXD_LENJUMBO_MASK (0x3FFF) /**< Jumbo frame length */
+
+#define GMAC_TXD_USED (1ul << 31) /**< Frame is transmitted */
+#define GMAC_TXD_WRAP (1ul << 30) /**< Last descriptor */
+#define GMAC_TXD_ERROR (1ul << 29) /**< Retry limit exceeded, error */
+#define GMAC_TXD_UNDERRUN (1ul << 28) /**< Transmit underrun */
+#define GMAC_TXD_EXHAUSTED (1ul << 27) /**< Buffer exhausted */
+#define GMAC_TXD_LATE (1ul << 26) /**< Late collision,transmit error */
+#define GMAC_TXD_CHECKSUM_ERROR (7ul << 20) /**< Checksum error */
+#define GMAC_TXD_NOCRC (1ul << 16) /**< No CRC */
+#define GMAC_TXD_LAST (1ul << 15) /**< Last buffer in frame */
+#define GMAC_TXD_LEN_MASK (0x1FFF) /**< Length of buffer */
+
+/** The MAC can support frame lengths up to 1536 bytes */
+#define GMAC_FRAME_LENTGH_MAX 1536
+
+#define GMAC_RX_UNITSIZE 128 /**< Fixed size for RX buffer */
+#define GMAC_TX_UNITSIZE 1518 /**< Size for ETH frame length */
+
+/** GMAC clock speed */
+#define GMAC_MCK_SPEED_240MHZ (240*1000*1000)
+#define GMAC_MCK_SPEED_160MHZ (160*1000*1000)
+#define GMAC_MCK_SPEED_120MHZ (120*1000*1000)
+#define GMAC_MCK_SPEED_80MHZ (80*1000*1000)
+#define GMAC_MCK_SPEED_40MHZ (40*1000*1000)
+#define GMAC_MCK_SPEED_20MHZ (20*1000*1000)
+
+/** GMAC maintain code default value*/
+#define GMAC_MAN_CODE_VALUE (10)
+
+/** GMAC maintain start of frame default value*/
+#define GMAC_MAN_SOF_VALUE (1)
+
+/** GMAC maintain read/write*/
+#define GMAC_MAN_RW_TYPE (2)
+
+/** GMAC maintain read only*/
+#define GMAC_MAN_READ_ONLY (1)
+
+/** GMAC address length */
+#define GMAC_ADDR_LENGTH (6)
+
+
+#define GMAC_DUPLEX_HALF 0
+#define GMAC_DUPLEX_FULL 1
+
+#define GMAC_SPEED_10M 0
+#define GMAC_SPEED_100M 1
+
+/**
+ * \brief Return codes for GMAC APIs.
+ */
+typedef enum {
+ GMAC_OK = 0, /** 0 Operation OK */
+ GMAC_TIMEOUT = 1, /** 1 GMAC operation timeout */
+ GMAC_TX_BUSY, /** 2 TX in progress */
+ GMAC_RX_NULL, /** 3 No data received */
+ GMAC_SIZE_TOO_SMALL, /** 4 Buffer size not enough */
+ GMAC_PARAM, /** 5 Parameter error, TX packet invalid or RX size too small */
+ GMAC_INVALID = 0xFF, /* Invalid */
+} gmac_status_t;
+
+/**
+ * \brief Media Independent Interface (MII) type.
+ */
+typedef enum {
+ GMAC_PHY_MII = 0, /** MII mode */
+ GMAC_PHY_RMII = 1, /** Reduced MII mode */
+ GMAC_PHY_INVALID = 0xFF, /* Invalid mode*/
+} gmac_mii_mode_t;
+
+/** Receive buffer descriptor struct */
+COMPILER_PACK_SET(8)
+typedef struct gmac_rx_descriptor {
+ union gmac_rx_addr {
+ uint32_t val;
+ struct gmac_rx_addr_bm {
+ uint32_t b_ownership:1, /**< User clear, GMAC sets this to 1 once it has successfully written a frame to memory */
+ b_wrap:1, /**< Marks last descriptor in receive buffer */
+ addr_dw:30; /**< Address in number of DW */
+ } bm;
+ } addr; /**< Address, Wrap & Ownership */
+ union gmac_rx_status {
+ uint32_t val;
+ struct gmac_rx_status_bm {
+ uint32_t len:13, /** 0..12 Length of frame including FCS */
+ b_fcs:1, /** 13 Receive buffer offset, bits 13:12 of frame length for jumbo frame */
+ b_sof:1, /** 14 Start of frame */
+ b_eof:1, /** 15 End of frame */
+ b_cfi:1, /** 16 Concatenation Format Indicator */
+ vlan_priority:3, /** 17..19 VLAN priority (if VLAN detected) */
+ b_priority_detected:1, /** 20 Priority tag detected */
+ b_vlan_detected:1, /** 21 VLAN tag detected */
+ b_type_id_match:2, /** 22..23 Type ID match */
+ b_checksumoffload:1, /** 24 Checksum offload specific function */
+ b_addrmatch:2, /** 25..26 Address register match */
+ b_ext_addr_match:1, /** 27 External address match found */
+ reserved:1, /** 28 */
+ b_uni_hash_match:1, /** 29 Unicast hash match */
+ b_multi_hash_match:1, /** 30 Multicast hash match */
+ b_boardcast_detect:1; /** 31 Global broadcast address detected */
+ } bm;
+ } status;
+} gmac_rx_descriptor_t;
+
+/** Transmit buffer descriptor struct */
+COMPILER_PACK_SET(8)
+typedef struct gmac_tx_descriptor {
+ uint32_t addr;
+ union gmac_tx_status {
+ uint32_t val;
+ struct gmac_tx_status_bm {
+ uint32_t len:14, /** 0..13 Length of buffer */
+ reserved:1, /** 14 */
+ b_last_buffer:1, /** 15 Last buffer (in the current frame) */
+ b_no_crc:1, /** 16 No CRC */
+ reserved1:3, /** 17..19 */
+ b_checksumoffload:3, /** 20..22 Transmit checksum generation offload errors */
+ reserved2:3, /** 23..25 */
+ b_lco:1, /** 26 Late collision, transmit error detected */
+ b_exhausted:1, /** 27 Buffer exhausted in mid frame */
+ b_underrun:1, /** 28 Transmit underrun */
+ b_error:1, /** 29 Retry limit exceeded, error detected */
+ b_wrap:1, /** 30 Marks last descriptor in TD list */
+ b_used:1; /** 31 User clear, GMAC sets this to 1 once a frame has been successfully transmitted */
+ } bm;
+ } status;
+} gmac_tx_descriptor_t;
+
+COMPILER_PACK_RESET()
+
+/**
+ * \brief Input parameters when initializing the gmac module mode.
+ */
+typedef struct gmac_options {
+ /* Enable/Disable CopyAllFrame */
+ uint8_t uc_copy_all_frame;
+ /* Enable/Disable NoBroadCast */
+ uint8_t uc_no_boardcast;
+ /* MAC address */
+ uint8_t uc_mac_addr[GMAC_ADDR_LENGTH];
+} gmac_options_t;
+
+/** TX callback */
+typedef void (*gmac_dev_tx_cb_t) (uint32_t ul_status, uint8_t *puc_buffer);
+/** RX callback */
+typedef void (*gmac_dev_rx_cb_t) (uint32_t ul_status);
+/** Wakeup callback */
+typedef void (*gmac_dev_wakeup_cb_t) (void);
+
+/**
+ * GMAC driver structure.
+ */
+typedef struct gmac_device {
+
+ /** Pointer to HW register base */
+ Gmac *p_hw;
+ /**
+ * Pointer to allocated TX buffer.
+ * Section 3.6 of AMBA 2.0 spec states that burst should not cross
+ * 1K Boundaries.
+ * Receive buffer manager writes are burst of 2 words => 3 lsb bits
+ * of the address shall be set to 0.
+ */
+ uint8_t *p_tx_buffer;
+ /** Pointer to allocated RX buffer */
+ uint8_t *p_rx_buffer;
+ /** Pointer to Rx TDs (must be 8-byte aligned) */
+ gmac_rx_descriptor_t *p_rx_dscr;
+ /** Pointer to Tx TDs (must be 8-byte aligned) */
+ gmac_tx_descriptor_t *p_tx_dscr;
+ /** Optional callback to be invoked once a frame has been received */
+ gmac_dev_rx_cb_t func_rx_cb;
+#if( GMAC_USES_WAKEUP_CALLBACK )
+ /** Optional callback to be invoked once several TDs have been released */
+ gmac_dev_wakeup_cb_t func_wakeup_cb;
+#endif
+#if( GMAC_USES_TX_CALLBACK != 0 )
+ /** Optional callback list to be invoked once TD has been processed */
+ gmac_dev_tx_cb_t *func_tx_cb_list;
+#endif
+ /** RX TD list size */
+ uint32_t ul_rx_list_size;
+ /** RX index for current processing TD */
+ uint32_t ul_rx_idx;
+ /** TX TD list size */
+ uint32_t ul_tx_list_size;
+ /** Circular buffer head pointer by upper layer (buffer to be sent) */
+ int32_t l_tx_head;
+ /** Circular buffer tail pointer incremented by handlers (buffer sent) */
+ int32_t l_tx_tail;
+
+ /** Number of free TD before wakeup callback is invoked */
+ uint32_t uc_wakeup_threshold;
+} gmac_device_t;
+
+/**
+ * \brief Write network control value.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_ncr Network control value.
+ */
+static inline void gmac_network_control(Gmac* p_gmac, uint32_t ul_ncr)
+{
+ p_gmac->GMAC_NCR = ul_ncr;
+}
+
+/**
+ * \brief Get network control value.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+
+static inline uint32_t gmac_get_network_control(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_NCR;
+}
+
+/**
+ * \brief Enable/Disable GMAC receive.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable GMAC receiver, else to enable it.
+ */
+static inline void gmac_enable_receive(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_RXEN;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_RXEN;
+ }
+}
+
+/**
+ * \brief Enable/Disable GMAC transmit.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable GMAC transmit, else to enable it.
+ */
+static inline void gmac_enable_transmit(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_TXEN;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_TXEN;
+ }
+}
+
+/**
+ * \brief Enable/Disable GMAC management.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable GMAC management, else to enable it.
+ */
+static inline void gmac_enable_management(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_MPE;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_MPE;
+ }
+}
+
+/**
+ * \brief Clear all statistics registers.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_clear_statistics(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_CLRSTAT;
+}
+
+/**
+ * \brief Increase all statistics registers.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_increase_statistics(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_INCSTAT;
+}
+
+/**
+ * \brief Enable/Disable statistics registers writing.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the statistics registers writing, else to enable it.
+ */
+static inline void gmac_enable_statistics_write(Gmac* p_gmac,
+ uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_WESTAT;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_WESTAT;
+ }
+}
+
+/**
+ * \brief In half-duplex mode, forces collisions on all received frames.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the back pressure, else to enable it.
+ */
+static inline void gmac_enable_back_pressure(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_BP;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_BP;
+ }
+}
+
+/**
+ * \brief Start transmission.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_start_transmission(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_TSTART;
+}
+
+/**
+ * \brief Halt transmission.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_halt_transmission(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_THALT;
+}
+
+/**
+ * \brief Transmit pause frame.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_tx_pause_frame(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_TXPF;
+}
+
+/**
+ * \brief Transmit zero quantum pause frame.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_tx_pause_zero_quantum_frame(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_TXZQPF;
+}
+
+/**
+ * \brief Read snapshot.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_read_snapshot(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_RDS;
+}
+
+/**
+ * \brief Store receivetime stamp to memory.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to normal operation, else to enable the store.
+ */
+static inline void gmac_store_rx_time_stamp(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_SRTSM;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_SRTSM;
+ }
+}
+
+/**
+ * \brief Enable PFC priority-based pause reception.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 1 to set the reception, 0 to disable.
+ */
+static inline void gmac_enable_pfc_pause_frame(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCR |= GMAC_NCR_ENPBPR;
+ } else {
+ p_gmac->GMAC_NCR &= ~GMAC_NCR_ENPBPR;
+ }
+}
+
+/**
+ * \brief Transmit PFC priority-based pause reception.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_transmit_pfc_pause_frame(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_TXPBPF;
+}
+
+/**
+ * \brief Flush next packet.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_flush_next_packet(Gmac* p_gmac)
+{
+ p_gmac->GMAC_NCR |= GMAC_NCR_FNP;
+}
+
+/**
+ * \brief Set up network configuration register.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_cfg Network configuration value.
+ */
+static inline void gmac_set_configure(Gmac* p_gmac, uint32_t ul_cfg)
+{
+ p_gmac->GMAC_NCFGR = ul_cfg;
+}
+
+/**
+ * \brief Get network configuration.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Network configuration.
+ */
+static inline uint32_t gmac_get_configure(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_NCFGR;
+}
+
+
+/* Get and set DMA Configuration Register */
+static inline void gmac_set_dma(Gmac* p_gmac, uint32_t ul_cfg)
+{
+ p_gmac->GMAC_DCFGR = ul_cfg;
+}
+
+static inline uint32_t gmac_get_dma(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_DCFGR;
+}
+
+/**
+ * \brief Set speed.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_speed 1 to indicate 100Mbps, 0 to 10Mbps.
+ */
+static inline void gmac_set_speed(Gmac* p_gmac, uint8_t uc_speed)
+{
+ if (uc_speed) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_SPD;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_SPD;
+ }
+}
+
+/**
+ * \brief Enable/Disable Full-Duplex mode.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the Full-Duplex mode, else to enable it.
+ */
+static inline void gmac_enable_full_duplex(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_FD;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_FD;
+ }
+}
+
+/**
+ * \brief Enable/Disable Copy(Receive) All Valid Frames.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable copying all valid frames, else to enable it.
+ */
+static inline void gmac_enable_copy_all(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_CAF;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_CAF;
+ }
+}
+
+/**
+ * \brief Enable/Disable jumbo frames (up to 10240 bytes).
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the jumbo frames, else to enable it.
+ */
+static inline void gmac_enable_jumbo_frames(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_JFRAME;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_JFRAME;
+ }
+}
+
+/**
+ * \brief Disable/Enable broadcast receiving.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 1 to disable the broadcast, else to enable it.
+ */
+static inline void gmac_disable_broadcast(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_NBC;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_NBC;
+ }
+}
+
+/**
+ * \brief Enable/Disable multicast hash.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the multicast hash, else to enable it.
+ */
+static inline void gmac_enable_multicast_hash(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_UNIHEN;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_UNIHEN;
+ }
+}
+
+/**
+ * \brief Enable/Disable big frames (over 1518, up to 1536).
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable big frames else to enable it.
+ */
+static inline void gmac_enable_big_frame(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_MAXFS;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_MAXFS;
+ }
+}
+
+/**
+ * \brief Set MDC clock divider.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_mck GMAC MCK.
+ *
+ * \return GMAC_OK if successfully.
+ */
+static inline uint8_t gmac_set_mdc_clock(Gmac* p_gmac, uint32_t ul_mck)
+{
+ uint32_t ul_clk;
+
+ if (ul_mck > GMAC_MCK_SPEED_240MHZ) {
+ return GMAC_INVALID;
+ } else if (ul_mck > GMAC_MCK_SPEED_160MHZ) {
+ ul_clk = GMAC_NCFGR_CLK_MCK_96;
+ } else if (ul_mck > GMAC_MCK_SPEED_120MHZ) {
+ ul_clk = GMAC_NCFGR_CLK_MCK_64;
+ } else if (ul_mck > GMAC_MCK_SPEED_80MHZ) {
+ ul_clk = GMAC_NCFGR_CLK_MCK_48;
+ } else if (ul_mck > GMAC_MCK_SPEED_40MHZ) {
+ ul_clk = GMAC_NCFGR_CLK_MCK_32;
+ } else if (ul_mck > GMAC_MCK_SPEED_20MHZ) {
+ ul_clk = GMAC_NCFGR_CLK_MCK_16;
+ } else {
+ ul_clk = GMAC_NCFGR_CLK_MCK_8;
+ }
+ ;
+ p_gmac->GMAC_NCFGR = (p_gmac->GMAC_NCFGR & ~GMAC_NCFGR_CLK_Msk) | ul_clk;
+ return GMAC_OK;
+}
+
+/**
+ * \brief Enable/Disable retry test.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the GMAC receiver, else to enable it.
+ */
+static inline void gmac_enable_retry_test(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RTY;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RTY;
+ }
+}
+
+/**
+ * \brief Enable/Disable pause (when a valid pause frame is received).
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable pause frame, else to enable it.
+ */
+static inline void gmac_enable_pause_frame(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_PEN;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_PEN;
+ }
+}
+
+/**
+ * \brief Set receive buffer offset to 0 ~ 3.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline void gmac_set_rx_buffer_offset(Gmac* p_gmac, uint8_t uc_offset)
+{
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RXBUFO_Msk;
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RXBUFO(uc_offset);
+}
+
+/**
+ * \brief Enable/Disable receive length field checking.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable receive length field checking, else to enable it.
+ */
+static inline void gmac_enable_rx_length_check(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_LFERD;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_LFERD;
+ }
+}
+
+/**
+ * \brief Enable/Disable discarding FCS field of received frames.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable discarding FCS field of received frames, else to enable it.
+ */
+static inline void gmac_enable_discard_fcs(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RFCS;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RFCS;
+ }
+}
+
+
+/**
+ * \brief Enable/Disable frames to be received in half-duplex mode
+ * while transmitting.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable the received in half-duplex mode, else to enable it.
+ */
+static inline void gmac_enable_efrhd(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_EFRHD;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_EFRHD;
+ }
+}
+
+/**
+ * \brief Enable/Disable ignore RX FCS.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_enable 0 to disable ignore RX FCS, else to enable it.
+ */
+static inline void gmac_enable_ignore_rx_fcs(Gmac* p_gmac, uint8_t uc_enable)
+{
+ if (uc_enable) {
+ p_gmac->GMAC_NCFGR |= GMAC_NCFGR_IRXFCS;
+ } else {
+ p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_IRXFCS;
+ }
+}
+
+/**
+ * \brief Get Network Status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Network status.
+ */
+static inline uint32_t gmac_get_status(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_NSR;
+}
+
+/**
+ * \brief Get MDIO IN pin status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return MDIO IN pin status.
+ */
+static inline uint8_t gmac_get_MDIO(Gmac* p_gmac)
+{
+ return ((p_gmac->GMAC_NSR & GMAC_NSR_MDIO) > 0);
+}
+
+/**
+ * \brief Check if PHY is idle.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return 1 if PHY is idle.
+ */
+static inline uint8_t gmac_is_phy_idle(Gmac* p_gmac)
+{
+ return ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) > 0);
+}
+
+/**
+ * \brief Return transmit status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Transmit status.
+ */
+static inline uint32_t gmac_get_tx_status(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_TSR;
+}
+
+/**
+ * \brief Clear transmit status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_status Transmit status.
+ */
+static inline void gmac_clear_tx_status(Gmac* p_gmac, uint32_t ul_status)
+{
+ p_gmac->GMAC_TSR = ul_status;
+}
+
+/**
+ * \brief Return receive status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ */
+static inline uint32_t gmac_get_rx_status(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_RSR;
+}
+
+/**
+ * \brief Clear receive status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_status Receive status.
+ */
+static inline void gmac_clear_rx_status(Gmac* p_gmac, uint32_t ul_status)
+{
+ p_gmac->GMAC_RSR = ul_status;
+}
+
+/**
+ * \brief Set Rx Queue.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_addr Rx queue address.
+ */
+static inline void gmac_set_rx_queue(Gmac* p_gmac, uint32_t ul_addr)
+{
+ p_gmac->GMAC_RBQB = GMAC_RBQB_ADDR_Msk & ul_addr;
+}
+
+/**
+ * \brief Get Rx Queue Address.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Rx queue address.
+ */
+static inline uint32_t gmac_get_rx_queue(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_RBQB;
+}
+
+/**
+ * \brief Set Tx Queue.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_addr Tx queue address.
+ */
+static inline void gmac_set_tx_queue(Gmac* p_gmac, uint32_t ul_addr)
+{
+ p_gmac->GMAC_TBQB = GMAC_TBQB_ADDR_Msk & ul_addr;
+}
+
+/**
+ * \brief Get Tx Queue.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Rx queue address.
+ */
+static inline uint32_t gmac_get_tx_queue(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_TBQB;
+}
+
+/**
+ * \brief Enable interrupt(s).
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_source Interrupt source(s) to be enabled.
+ */
+static inline void gmac_enable_interrupt(Gmac* p_gmac, uint32_t ul_source)
+{
+ p_gmac->GMAC_IER = ul_source;
+}
+
+/**
+ * \brief Disable interrupt(s).
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_source Interrupt source(s) to be disabled.
+ */
+static inline void gmac_disable_interrupt(Gmac* p_gmac, uint32_t ul_source)
+{
+ p_gmac->GMAC_IDR = ul_source;
+}
+
+/**
+ * \brief Return interrupt status.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Interrupt status.
+ */
+static inline uint32_t gmac_get_interrupt_status(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_ISR;
+}
+
+/**
+ * \brief Return interrupt mask.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Interrupt mask.
+ */
+static inline uint32_t gmac_get_interrupt_mask(Gmac* p_gmac)
+{
+ return p_gmac->GMAC_IMR;
+}
+
+/**
+ * \brief Execute PHY maintenance command.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_phy_addr PHY address.
+ * \param uc_reg_addr Register address.
+ * \param uc_rw 1 to Read, 0 to write.
+ * \param us_data Data to be performed, write only.
+ */
+static inline void gmac_maintain_phy(Gmac* p_gmac,
+ uint8_t uc_phy_addr, uint8_t uc_reg_addr, uint8_t uc_rw,
+ uint16_t us_data)
+{
+ /* Wait until bus idle */
+ while ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) == 0);
+ /* Write maintain register */
+ p_gmac->GMAC_MAN = GMAC_MAN_WTN(GMAC_MAN_CODE_VALUE)
+ | GMAC_MAN_CLTTO
+ | GMAC_MAN_PHYA(uc_phy_addr)
+ | GMAC_MAN_REGA(uc_reg_addr)
+ | GMAC_MAN_OP((uc_rw ? GMAC_MAN_RW_TYPE : GMAC_MAN_READ_ONLY))
+ | GMAC_MAN_DATA(us_data);
+}
+
+/**
+ * \brief Get PHY maintenance data returned.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ *
+ * \return Get PHY data.
+ */
+static inline uint16_t gmac_get_phy_data(Gmac* p_gmac)
+{
+ /* Wait until bus idle */
+ while ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) == 0);
+ /* Return data */
+ return (uint16_t) (p_gmac->GMAC_MAN & GMAC_MAN_DATA_Msk);
+}
+
+/**
+ * \brief Set Hash.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ul_hash_top Hash top.
+ * \param ul_hash_bottom Hash bottom.
+ */
+static inline void gmac_set_hash(Gmac* p_gmac, uint32_t ul_hash_top,
+ uint32_t ul_hash_bottom)
+{
+ p_gmac->GMAC_HRB = ul_hash_bottom;
+ p_gmac->GMAC_HRT = ul_hash_top;
+}
+
+/**
+ * \brief Set 64 bits Hash.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param ull_hash 64 bits hash value.
+ */
+static inline void gmac_set_hash64(Gmac* p_gmac, uint64_t ull_hash)
+{
+ p_gmac->GMAC_HRB = (uint32_t) ull_hash;
+ p_gmac->GMAC_HRT = (uint32_t) (ull_hash >> 32);
+}
+
+/**
+ * \brief Set MAC Address.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_index GMAC specific address register index.
+ * \param p_mac_addr GMAC address.
+ */
+static inline void gmac_set_address(Gmac* p_gmac, uint8_t uc_index,
+ uint8_t* p_mac_addr)
+{
+ p_gmac->GMAC_SA[uc_index].GMAC_SAB = (p_mac_addr[3] << 24)
+ | (p_mac_addr[2] << 16)
+ | (p_mac_addr[1] << 8)
+ | (p_mac_addr[0]);
+ p_gmac->GMAC_SA[uc_index].GMAC_SAT = (p_mac_addr[5] << 8)
+ | (p_mac_addr[4]);
+}
+
+/**
+ * \brief Set MAC Address via 2 dword.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_index GMAC specific address register index.
+ * \param ul_mac_top GMAC top address.
+ * \param ul_mac_bottom GMAC bottom address.
+ */
+static inline void gmac_set_address32(Gmac* p_gmac, uint8_t uc_index,
+ uint32_t ul_mac_top, uint32_t ul_mac_bottom)
+{
+ p_gmac->GMAC_SA[uc_index].GMAC_SAB = ul_mac_bottom;
+ p_gmac->GMAC_SA[uc_index].GMAC_SAT = ul_mac_top;
+}
+
+/**
+ * \brief Set MAC Address via int64.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param uc_index GMAC specific address register index.
+ * \param ull_mac 64-bit GMAC address.
+ */
+static inline void gmac_set_address64(Gmac* p_gmac, uint8_t uc_index,
+ uint64_t ull_mac)
+{
+ p_gmac->GMAC_SA[uc_index].GMAC_SAB = (uint32_t) ull_mac;
+ p_gmac->GMAC_SA[uc_index].GMAC_SAT = (uint32_t) (ull_mac >> 32);
+}
+
+/**
+ * \brief Select media independent interface mode.
+ *
+ * \param p_gmac Pointer to the GMAC instance.
+ * \param mode Media independent interface mode.
+ */
+static inline void gmac_select_mii_mode(Gmac* p_gmac, gmac_mii_mode_t mode)
+{
+ switch (mode) {
+ case GMAC_PHY_MII:
+ case GMAC_PHY_RMII:
+ p_gmac->GMAC_UR |= GMAC_UR_RMIIMII;
+ break;
+
+ default:
+ p_gmac->GMAC_UR &= ~GMAC_UR_RMIIMII;
+ break;
+ }
+}
+
+uint8_t gmac_phy_read(Gmac* p_gmac, uint8_t uc_phy_address, uint8_t uc_address,
+ uint32_t* p_value);
+uint8_t gmac_phy_write(Gmac* p_gmac, uint8_t uc_phy_address,
+ uint8_t uc_address, uint32_t ul_value);
+void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev,
+ gmac_options_t* p_opt);
+uint32_t gmac_dev_read(gmac_device_t* p_gmac_dev, uint8_t* p_frame,
+ uint32_t ul_frame_size, uint32_t* p_rcv_size);
+uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer,
+ uint32_t ul_size, gmac_dev_tx_cb_t func_tx_cb);
+uint32_t gmac_dev_get_tx_load(gmac_device_t* p_gmac_dev);
+void gmac_dev_set_rx_callback(gmac_device_t* p_gmac_dev,
+ gmac_dev_rx_cb_t func_rx_cb);
+uint8_t gmac_dev_set_tx_wakeup_callback(gmac_device_t* p_gmac_dev,
+ gmac_dev_wakeup_cb_t func_wakeup, uint8_t uc_threshold);
+void gmac_dev_reset(gmac_device_t* p_gmac_dev);
+void gmac_handler(gmac_device_t* p_gmac_dev);
+
+/// @cond 0
+/**INDENT-OFF**/
+#ifdef __cplusplus
+}
+#endif
+/**INDENT-ON**/
+/// @endcond
+
+/**
+ * \page gmac_quickstart Quickstart guide for GMAC driver.
+ *
+ * This is the quickstart guide for the \ref gmac_group "Ethernet MAC",
+ * with step-by-step instructions on how to configure and use the driver in a
+ * selection of use cases.
+ *
+ * The use cases contain several code fragments. The code fragments in the
+ * steps for setup can be copied into a custom initialization function, while
+ * the steps for usage can be copied into, e.g., the main application function.
+ *
+ * \section gmac_basic_use_case Basic use case
+ * In the basic use case, the GMAC driver are configured for:
+ * - PHY component KSZ8051MNL is used
+ * - GMAC uses MII mode
+ * - The number of receive buffer is 16
+ * - The number of transfer buffer is 8
+ * - MAC address is set to 00-04-25-1c-a0-02
+ * - IP address is set to 192.168.0.2
+ * - IP address is set to 192.168.0.2
+ * - Gateway is set to 192.168.0.1
+ * - Network mask is 255.255.255.0
+ * - PHY operation max retry count is 1000000
+ * - GMAC is configured to not support copy all frame and support broadcast
+ * - The data will be read from the ethernet
+ *
+ * \section gmac_basic_use_case_setup Setup steps
+ *
+ * \subsection gmac_basic_use_case_setup_prereq Prerequisites
+ * -# \ref sysclk_group "System Clock Management (sysclock)"
+ * -# \ref pmc_group "Power Management Controller (pmc)"
+ * -# \ref ksz8051mnl_ethernet_phy_group "PHY component (KSZ8051MNL)"
+ *
+ * \subsection gmac_basic_use_case_setup_code Example code
+ * Content of conf_eth.h
+ * \code
+ * #define GMAC_RX_BUFFERS 16
+ * #define GMAC_TX_BUFFERS 8
+ * #define MAC_PHY_RETRY_MAX 1000000
+ * #define ETHERNET_CONF_ETHADDR0 0x00
+ * #define ETHERNET_CONF_ETHADDR0 0x00
+ * #define ETHERNET_CONF_ETHADDR1 0x04
+ * #define ETHERNET_CONF_ETHADDR2 0x25
+ * #define ETHERNET_CONF_ETHADDR3 0x1C
+ * #define ETHERNET_CONF_ETHADDR4 0xA0
+ * #define ETHERNET_CONF_ETHADDR5 0x02
+ * #define ETHERNET_CONF_IPADDR0 192
+ * #define ETHERNET_CONF_IPADDR1 168
+ * #define ETHERNET_CONF_IPADDR2 0
+ * #define ETHERNET_CONF_IPADDR3 2
+ * #define ETHERNET_CONF_GATEWAY_ADDR0 192
+ * #define ETHERNET_CONF_GATEWAY_ADDR1 168
+ * #define ETHERNET_CONF_GATEWAY_ADDR2 0
+ * #define ETHERNET_CONF_GATEWAY_ADDR3 1
+ * #define ETHERNET_CONF_NET_MASK0 255
+ * #define ETHERNET_CONF_NET_MASK1 255
+ * #define ETHERNET_CONF_NET_MASK2 255
+ * #define ETHERNET_CONF_NET_MASK3 0
+ * #define ETH_PHY_MODE ETH_PHY_MODE
+ * \endcode
+ *
+ * A specific gmac device and the receive data buffer must be defined; another ul_frm_size should be defined
+ * to trace the actual size of the data received.
+ * \code
+ * static gmac_device_t gs_gmac_dev;
+ * static volatile uint8_t gs_uc_eth_buffer[GMAC_FRAME_LENTGH_MAX];
+ *
+ * uint32_t ul_frm_size;
+ * \endcode
+ *
+ * Add to application C-file:
+ * \code
+ * void gmac_init(void)
+ * {
+ * sysclk_init();
+ *
+ * board_init();
+ *
+ * pmc_enable_periph_clk(ID_GMAC);
+ *
+ * gmac_option.uc_copy_all_frame = 0;
+ * gmac_option.uc_no_boardcast = 0;
+ * memcpy(gmac_option.uc_mac_addr, gs_uc_mac_address, sizeof(gs_uc_mac_address));
+ * gs_gmac_dev.p_hw = GMAC;
+ *
+ * gmac_dev_init(GMAC, &gs_gmac_dev, &gmac_option);
+ *
+ * NVIC_EnableIRQ(GMAC_IRQn);
+ *
+ * ethernet_phy_init(GMAC, BOARD_GMAC_PHY_ADDR, sysclk_get_cpu_hz());
+ *
+ * ethernet_phy_auto_negotiate(GMAC, BOARD_GMAC_PHY_ADDR);
+ *
+ * ethernet_phy_set_link(GMAC, BOARD_GMAC_PHY_ADDR, 1);
+ * \endcode
+ *
+ * \subsection gmac_basic_use_case_setup_flow Workflow
+ * - Ensure that conf_eth.h is present and contains the
+ * following configuration symbol. This configuration file is used
+ * by the driver and should not be included by the application.
+ * -# Define the receiving buffer size used in the internal GMAC driver.
+ * The buffer size used for RX is GMAC_RX_BUFFERS * 128.
+ * If it was supposed receiving a large number of frame, the
+ * GMAC_RX_BUFFERS should be set higher. E.g., the application wants to accept
+ * a ping echo test of 2048, the GMAC_RX_BUFFERS should be set at least
+ * (2048/128)=16, and as there are additional frames coming, a preferred
+ * number is 24 depending on a normal Ethernet throughput.
+ * - \code
+ * #define GMAC_RX_BUFFERS 16
+ * \endcode
+ * -# Define the transmitting buffer size used in the internal GMAC driver.
+ * The buffer size used for TX is GMAC_TX_BUFFERS * 1518.
+ * - \code
+ * #define GMAC_TX_BUFFERS 8
+ * \endcode
+ * -# Define maximum retry time for a PHY read/write operation.
+ * - \code
+ * #define MAC_PHY_RETRY_MAX 1000000
+ * \endcode
+ * -# Define the MAC address. 00:04:25:1C:A0:02 is the address reserved
+ * for ATMEL, application should always change this address to its' own.
+ * - \code
+ * #define ETHERNET_CONF_ETHADDR0 0x00
+ * #define ETHERNET_CONF_ETHADDR1 0x04
+ * #define ETHERNET_CONF_ETHADDR2 0x25
+ * #define ETHERNET_CONF_ETHADDR3 0x1C
+ * #define ETHERNET_CONF_ETHADDR4 0xA0
+ * #define ETHERNET_CONF_ETHADDR5 0x02
+ * \endcode
+ * -# Define the IP address configration used in the application. When DHCP
+ * is enabled, this configuration is not effected.
+ * - \code
+ * #define ETHERNET_CONF_IPADDR0 192
+ * #define ETHERNET_CONF_IPADDR1 168
+ * #define ETHERNET_CONF_IPADDR2 0
+ * #define ETHERNET_CONF_IPADDR3 2
+ * #define ETHERNET_CONF_GATEWAY_ADDR0 192
+ * #define ETHERNET_CONF_GATEWAY_ADDR1 168
+ * #define ETHERNET_CONF_GATEWAY_ADDR2 0
+ * #define ETHERNET_CONF_GATEWAY_ADDR3 1
+ * #define ETHERNET_CONF_NET_MASK0 255
+ * #define ETHERNET_CONF_NET_MASK1 255
+ * #define ETHERNET_CONF_NET_MASK2 255
+ * #define ETHERNET_CONF_NET_MASK3 0
+ * \endcode
+ * -# Configure the PHY maintainance interface.
+ * - \code
+ * #define ETH_PHY_MODE GMAC_PHY_MII
+ * \endcode
+ * -# Enable the system clock:
+ * - \code sysclk_init(); \endcode
+ * -# Enable PIO configurations for GMAC:
+ * - \code board_init(); \endcode
+ * -# Enable PMC clock for GMAC:
+ * - \code pmc_enable_periph_clk(ID_GMAC); \endcode
+ * -# Set the GMAC options; it's set to copy all frame and support broadcast:
+ * - \code
+ * gmac_option.uc_copy_all_frame = 0;
+ * gmac_option.uc_no_boardcast = 0;
+ * memcpy(gmac_option.uc_mac_addr, gs_uc_mac_address, sizeof(gs_uc_mac_address));
+ * gs_gmac_dev.p_hw = GMAC;
+ * \endcode
+ * -# Initialize GMAC device with the filled option:
+ * - \code
+ * gmac_dev_init(GMAC, &gs_gmac_dev, &gmac_option);
+ * \endcode
+ * -# Enable the interrupt service for GMAC:
+ * - \code
+ * NVIC_EnableIRQ(GMAC_IRQn);
+ * \endcode
+ * -# Initialize the PHY component:
+ * - \code
+ * ethernet_phy_init(GMAC, BOARD_GMAC_PHY_ADDR, sysclk_get_cpu_hz());
+ * \endcode
+ * -# The link will be established based on auto negotiation.
+ * - \code
+ * ethernet_phy_auto_negotiate(GMAC, BOARD_GMAC_PHY_ADDR);
+ * \endcode
+ * -# Establish the ethernet link; the network can be worked from now on:
+ * - \code
+ * ethernet_phy_set_link(GMAC, BOARD_GMAC_PHY_ADDR, 1);
+ * \endcode
+ *
+ * \section gmac_basic_use_case_usage Usage steps
+ * \subsection gmac_basic_use_case_usage_code Example code
+ * Add to, e.g., main loop in application C-file:
+ * \code
+ * gmac_dev_read(&gs_gmac_dev, (uint8_t *) gs_uc_eth_buffer, sizeof(gs_uc_eth_buffer), &ul_frm_size));
+ * \endcode
+ *
+ * \subsection gmac_basic_use_case_usage_flow Workflow
+ * -# Start reading the data from the ethernet:
+ * - \code gmac_dev_read(&gs_gmac_dev, (uint8_t *) gs_uc_eth_buffer, sizeof(gs_uc_eth_buffer), &ul_frm_size)); \endcode
+ */
+
+# define GMAC_STATS 0
+
+#if( GMAC_STATS != 0 )
+
+ /* Here below some code to study the types and
+ frequencies of GMAC interrupts. */
+ #define GMAC_IDX_RXUBR 0
+ #define GMAC_IDX_TUR 1
+ #define GMAC_IDX_RLEX 2
+ #define GMAC_IDX_TFC 3
+ #define GMAC_IDX_RCOMP 4
+ #define GMAC_IDX_TCOMP 5
+ #define GMAC_IDX_ROVR 6
+ #define GMAC_IDX_HRESP 7
+ #define GMAC_IDX_PFNZ 8
+ #define GMAC_IDX_PTZ 9
+
+ struct SGmacStats {
+ unsigned recvCount;
+ unsigned rovrCount;
+ unsigned bnaCount;
+ unsigned sendCount;
+ unsigned sovrCount;
+ unsigned incompCount;
+ unsigned truncCount;
+
+ unsigned intStatus[10];
+ };
+ extern struct SGmacStats gmacStats;
+
+ struct SIntPair {
+ const char *name;
+ unsigned mask;
+ int index;
+ };
+
+ #define MK_PAIR( NAME ) #NAME, GMAC_IER_##NAME, GMAC_IDX_##NAME
+ static const struct SIntPair intPairs[] = {
+ { MK_PAIR( RXUBR ) }, /* Enable receive used bit read interrupt. */
+ { MK_PAIR( TUR ) }, /* Enable transmit underrun interrupt. */
+ { MK_PAIR( RLEX ) }, /* Enable retry limit exceeded interrupt. */
+ { MK_PAIR( TFC ) }, /* Enable transmit buffers exhausted in mid-frame interrupt. */
+ { MK_PAIR( RCOMP ) }, /* Receive complete */
+ { MK_PAIR( TCOMP ) }, /* Enable transmit complete interrupt. */
+ { MK_PAIR( ROVR ) }, /* Enable receive overrun interrupt. */
+ { MK_PAIR( HRESP ) }, /* Enable Hresp not OK interrupt. */
+ { MK_PAIR( PFNZ ) }, /* Enable pause frame received interrupt. */
+ { MK_PAIR( PTZ ) } /* Enable pause time zero interrupt. */
+ };
+
+ void gmac_show_irq_counts ();
+
+#endif
+
+#endif /* GMAC_H_INCLUDED */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c
new file mode 100644
index 000000000..66d4282b9
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c
@@ -0,0 +1,293 @@
+/*
+ * FreeRTOS+TCP Labs Build 150406 (C) 2015 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB: ***
+ *** ***
+ *** This product is functional and is already being used in commercial ***
+ *** products. Be aware however that we are still refining its design, ***
+ *** the source code does not yet fully conform to the strict coding and ***
+ *** style standards mandated by Real Time Engineers ltd., and the ***
+ *** documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * - Open source licensing -
+ * While FreeRTOS+TCP is in the lab it is provided only under version two of the
+ * GNU General Public License (GPL) (which is different to the standard FreeRTOS
+ * license). FreeRTOS+TCP is free to download, use and distribute under the
+ * terms of that license provided the copyright notice and this text are not
+ * altered or removed from the source files. The GPL V2 text is available on
+ * the gnu.org web site, and on the following
+ * URL: http://www.FreeRTOS.org/gpl-2.0.txt. Active early adopters may, and
+ * solely at the discretion of Real Time Engineers Ltd., be offered versions
+ * under a license other then the GPL.
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* Hardware abstraction. */
+#include "FreeRTOS_IO.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "NetworkBufferManagement.h"
+
+/* Driver includes. */
+#include "lpc17xx_emac.h"
+#include "lpc17xx_pinsel.h"
+
+/* Demo includes. */
+#include "NetworkInterface.h"
+
+#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
+ #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
+#else
+ #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
+#endif
+
+/* When a packet is ready to be sent, if it cannot be sent immediately then the
+task performing the transmit will block for niTX_BUFFER_FREE_WAIT
+milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving
+up. */
+#define niTX_BUFFER_FREE_WAIT ( pdMS_TO_TICKS( 2UL ) )
+#define niMAX_TX_ATTEMPTS ( 5 )
+
+/* The length of the queue used to send interrupt status words from the
+interrupt handler to the deferred handler task. */
+#define niINTERRUPT_QUEUE_LENGTH ( 10 )
+
+/*-----------------------------------------------------------*/
+
+/*
+ * A deferred interrupt handler task that processes
+ */
+static void prvEMACHandlerTask( void *pvParameters );
+
+/*-----------------------------------------------------------*/
+
+/* The queue used to communicate Ethernet events with the IP task. */
+extern QueueHandle_t xNetworkEventQueue;
+
+/* The semaphore used to wake the deferred interrupt handler task when an Rx
+interrupt is received. */
+static SemaphoreHandle_t xEMACRxEventSemaphore = NULL;
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceInitialise( void )
+{
+EMAC_CFG_Type Emac_Config;
+PINSEL_CFG_Type xPinConfig;
+BaseType_t xStatus, xReturn;
+extern uint8_t ucMACAddress[ 6 ];
+
+ /* Enable Ethernet Pins */
+ boardCONFIGURE_ENET_PINS( xPinConfig );
+
+ Emac_Config.Mode = EMAC_MODE_AUTO;
+ Emac_Config.pbEMAC_Addr = ucMACAddress;
+ xStatus = EMAC_Init( &Emac_Config );
+
+ LPC_EMAC->IntEnable &= ~( EMAC_INT_TX_DONE );
+
+ if( xStatus != ERROR )
+ {
+ vSemaphoreCreateBinary( xEMACRxEventSemaphore );
+ configASSERT( xEMACRxEventSemaphore );
+
+ /* The handler task is created at the highest possible priority to
+ ensure the interrupt handler can return directly to it. */
+ xTaskCreate( prvEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
+
+ /* Enable the interrupt and set its priority to the minimum
+ interrupt priority. */
+ NVIC_SetPriority( ENET_IRQn, configMAC_INTERRUPT_PRIORITY );
+ NVIC_EnableIRQ( ENET_IRQn );
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+
+ configASSERT( xStatus != ERROR );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer )
+{
+BaseType_t xReturn = pdFAIL;
+int32_t x;
+extern void EMAC_StartTransmitNextBuffer( uint32_t ulLength );
+extern void EMAC_SetNextPacketToSend( uint8_t * pucBuffer );
+
+
+ /* Attempt to obtain access to a Tx buffer. */
+ for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )
+ {
+ if( EMAC_CheckTransmitIndex() == TRUE )
+ {
+ /* Will the data fit in the Tx buffer? */
+ if( pxNetworkBuffer->xDataLength < EMAC_ETH_MAX_FLEN ) /*_RB_ The size needs to come from FreeRTOSIPConfig.h. */
+ {
+ /* Assign the buffer to the Tx descriptor that is now known to
+ be free. */
+ EMAC_SetNextPacketToSend( pxNetworkBuffer->pucBuffer );
+
+ /* The EMAC now owns the buffer. */
+ pxNetworkBuffer->pucBuffer = NULL;
+
+ /* Initiate the Tx. */
+ EMAC_StartTransmitNextBuffer( pxNetworkBuffer->xDataLength );
+ iptraceNETWORK_INTERFACE_TRANSMIT();
+
+ /* The Tx has been initiated. */
+ xReturn = pdPASS;
+ }
+ break;
+ }
+ else
+ {
+ vTaskDelay( niTX_BUFFER_FREE_WAIT );
+ }
+ }
+
+ /* Finished with the network buffer. */
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void ENET_IRQHandler( void )
+{
+uint32_t ulInterruptCause;
+
+ while( ( ulInterruptCause = LPC_EMAC->IntStatus ) != 0 )
+ {
+ /* Clear the interrupt. */
+ LPC_EMAC->IntClear = ulInterruptCause;
+
+ /* Clear fatal error conditions. NOTE: The driver does not clear all
+ errors, only those actually experienced. For future reference, range
+ errors are not actually errors so can be ignored. */
+ if( ( ulInterruptCause & EMAC_INT_TX_UNDERRUN ) != 0U )
+ {
+ LPC_EMAC->Command |= EMAC_CR_TX_RES;
+ }
+
+ /* Unblock the deferred interrupt handler task if the event was an
+ Rx. */
+ if( ( ulInterruptCause & EMAC_INT_RX_DONE ) != 0UL )
+ {
+ xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );
+ }
+ }
+
+ /* ulInterruptCause is used for convenience here. A context switch is
+ wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a
+ compiler warning. */
+ portEND_SWITCHING_ISR( ulInterruptCause );
+}
+/*-----------------------------------------------------------*/
+
+static void prvEMACHandlerTask( void *pvParameters )
+{
+size_t xDataLength;
+const uint16_t usCRCLength = 4;
+NetworkBufferDescriptor_t *pxNetworkBuffer;
+IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
+
+/* This is not included in the header file for some reason. */
+extern uint8_t *EMAC_NextPacketToRead( void );
+
+ ( void ) pvParameters;
+ configASSERT( xEMACRxEventSemaphore );
+
+ for( ;; )
+ {
+ /* Wait for the EMAC interrupt to indicate that another packet has been
+ received. The while() loop is only needed if INCLUDE_vTaskSuspend is
+ set to 0 in FreeRTOSConfig.h. */
+ while( xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE );
+
+ /* At least one packet has been received. */
+ while( EMAC_CheckReceiveIndex() != FALSE )
+ {
+ /* Obtain the length, minus the CRC. The CRC is four bytes
+ but the length is already minus 1. */
+ xDataLength = ( size_t ) EMAC_GetReceiveDataSize() - ( usCRCLength - 1U );
+
+ if( xDataLength > 0U )
+ {
+ /* Obtain a network buffer to pass this data into the
+ stack. No storage is required as the network buffer
+ will point directly to the buffer that already holds
+ the received data. */
+ pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( 0, ( TickType_t ) 0 );
+
+ if( pxNetworkBuffer != NULL )
+ {
+ pxNetworkBuffer->pucBuffer = EMAC_NextPacketToRead();
+ pxNetworkBuffer->xDataLength = xDataLength;
+ xRxEvent.pvData = ( void * ) pxNetworkBuffer;
+
+ /* Data was received and stored. Send a message to the IP
+ task to let it know. */
+ if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ iptraceETHERNET_RX_EVENT_LOST();
+ }
+ }
+ else
+ {
+ iptraceETHERNET_RX_EVENT_LOST();
+ }
+
+ iptraceNETWORK_INTERFACE_RECEIVE();
+ }
+
+ /* Release the frame. */
+ EMAC_UpdateRxConsumeIndex();
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c
new file mode 100644
index 000000000..0f1019abc
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c
@@ -0,0 +1,1100 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.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 "NetworkBufferManagement.h"
+#include "NetworkInterface.h"
+
+/* LPCOpen includes. */
+#include "chip.h"
+#include "lpc_phy.h"
+
+/* The size of the stack allocated to the task that handles Rx packets. */
+#define nwRX_TASK_STACK_SIZE 140
+
+#ifndef PHY_LS_HIGH_CHECK_TIME_MS
+ /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
+ receiving packets. */
+ #define PHY_LS_HIGH_CHECK_TIME_MS 15000
+#endif
+
+#ifndef PHY_LS_LOW_CHECK_TIME_MS
+ /* Check if the LinkSStatus in the PHY is still low every second. */
+ #define PHY_LS_LOW_CHECK_TIME_MS 1000
+#endif
+
+#ifndef configUSE_RMII
+ #define configUSE_RMII 1
+#endif
+
+#ifndef configNUM_RX_DESCRIPTORS
+ #error please define configNUM_RX_DESCRIPTORS in your FreeRTOSIPConfig.h
+#endif
+
+#ifndef configNUM_TX_DESCRIPTORS
+ #error please define configNUM_TX_DESCRIPTORS in your FreeRTOSIPConfig.h
+#endif
+
+#ifndef NETWORK_IRQHandler
+ #error NETWORK_IRQHandler must be defined to the name of the function that is installed in the interrupt vector table to handle Ethernet interrupts.
+#endif
+
+#if !defined( MAC_FF_HMC )
+ /* Hash for multicast. */
+ #define MAC_FF_HMC ( 1UL << 2UL )
+#endif
+
+#ifndef iptraceEMAC_TASK_STARTING
+ #define iptraceEMAC_TASK_STARTING() do { } while( 0 )
+#endif
+
+/* Define the bits of .STATUS that indicate a reception error. */
+#define nwRX_STATUS_ERROR_BITS \
+ ( RDES_CE /* CRC Error */ | \
+ RDES_RE /* Receive Error */ | \
+ RDES_DE /* Descriptor Error */ | \
+ RDES_RWT /* Receive Watchdog Timeout */ | \
+ RDES_LC /* Late Collision */ | \
+ RDES_OE /* Overflow Error */ | \
+ RDES_SAF /* Source Address Filter Fail */ | \
+ RDES_AFM /* Destination Address Filter Fail */ | \
+ RDES_LE /* Length Error */ )
+
+/* Define the EMAC status bits that should trigger an interrupt. */
+#define nwDMA_INTERRUPT_MASK \
+ ( DMA_IE_TIE /* Transmit interrupt enable */ | \
+ DMA_IE_TSE /* Transmit stopped enable */ | \
+ DMA_IE_OVE /* Overflow interrupt enable */ | \
+ DMA_IE_RIE /* Receive interrupt enable */ | \
+ DMA_IE_NIE /* Normal interrupt summary enable */ | \
+ DMA_IE_AIE /* Abnormal interrupt summary enable */ | \
+ DMA_IE_RUE /* Receive buffer unavailable enable */ | \
+ DMA_IE_UNE /* Underflow interrupt enable. */ | \
+ DMA_IE_TJE /* Transmit jabber timeout enable */ | \
+ DMA_IE_RSE /* Received stopped enable */ | \
+ DMA_IE_RWE /* Receive watchdog timeout enable */ | \
+ DMA_IE_FBE )/* Fatal bus error enable */
+
+/* Interrupt events to process. Currently only the RX/TX events are processed
+although code for other events is included to allow for possible future
+expansion. */
+#define EMAC_IF_RX_EVENT 1UL
+#define EMAC_IF_TX_EVENT 2UL
+#define EMAC_IF_ERR_EVENT 4UL
+#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
+
+ /* 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. */
+ #if( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
+ #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
+ #else
+ #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
+ #endif
+
+#if( ipconfigZERO_COPY_RX_DRIVER == 0 ) || ( ipconfigZERO_COPY_TX_DRIVER == 0 )
+ #warning It is adviced to enable both macros
+#endif
+
+#ifndef configPLACE_IN_SECTION_RAM
+ #define configPLACE_IN_SECTION_RAM
+/*
+ #define configPLACE_IN_SECTION_RAM __attribute__ ((section(".ramfunc")))
+*/
+#endif
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Delay function passed into the library. The implementation uses FreeRTOS
+ * calls so the scheduler must be started before the driver can be used.
+ */
+static void prvDelay( uint32_t ulMilliSeconds );
+
+/*
+ * Initialises the Tx and Rx descriptors respectively.
+ */
+static void prvSetupTxDescriptors( void );
+static void prvSetupRxDescriptors( void );
+
+/*
+ * A task that processes received frames.
+ */
+static void prvEMACHandlerTask( void *pvParameters );
+
+/*
+ * Sets up the MAC with the results of an auto-negotiation.
+ */
+static BaseType_t prvSetLinkSpeed( void );
+
+/*
+ * Generates a CRC for a MAC address that is then used to generate a hash index.
+ */
+static uint32_t prvGenerateCRC32( const uint8_t *ucAddress );
+
+/*
+ * Generates a hash index when setting a filter to permit a MAC address.
+ */
+static uint32_t prvGetHashIndex( const uint8_t *ucAddress );
+
+/*
+ * Update the hash table to allow a MAC address.
+ */
+static void prvAddMACAddress( const uint8_t* ucMacAddress );
+
+/*
+ * Sometimes the DMA will report received data as being longer than the actual
+ * received from length. This function checks the reported length and corrects
+ * if if necessary.
+ */
+static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor );
+
+/*-----------------------------------------------------------*/
+
+/* Bit map of outstanding ETH interrupt events for processing. Currently only
+the Rx and Tx interrupt is handled, although code is included for other events
+to enable future expansion. */
+static volatile uint32_t ulISREvents;
+
+/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
+static uint32_t ulPHYLinkStatus = 0;
+
+/* Tx descriptors and index. */
+static ENET_ENHTXDESC_T xDMATxDescriptors[ configNUM_TX_DESCRIPTORS ];
+
+/* ulNextFreeTxDescriptor is declared volatile, because it is accessed from
+to different tasks. */
+static volatile uint32_t ulNextFreeTxDescriptor;
+static uint32_t ulTxDescriptorToClear;
+
+/* Rx descriptors and index. */
+static ENET_ENHRXDESC_T xDMARxDescriptors[ configNUM_RX_DESCRIPTORS ];
+static uint32_t ulNextRxDescriptorToProcess;
+
+/* Must be defined externally - the demo applications define this in main.c. */
+extern uint8_t ucMACAddress[ 6 ];
+
+/* The handle of the task that processes Rx packets. The handle is required so
+the task can be notified when new packets arrive. */
+static TaskHandle_t xRxHanderTask = NULL;
+
+#if( ipconfigUSE_LLMNR == 1 )
+ static const uint8_t xLLMNR_MACAddress[] = { '\x01', '\x00', '\x5E', '\x00', '\x00', '\xFC' };
+#endif /* ipconfigUSE_LLMNR == 1 */
+
+/* xTXDescriptorSemaphore is a counting semaphore with
+a maximum count of ETH_TXBUFNB, which is the number of
+DMA TX descriptors. */
+static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
+
+/*-----------------------------------------------------------*/
+
+
+BaseType_t xNetworkInterfaceInitialise( void )
+{
+BaseType_t xReturn = pdPASS;
+static BaseType_t xHasInitialised = pdFALSE;
+
+ if( xHasInitialised == pdFALSE )
+ {
+ xHasInitialised = pdTRUE;
+
+ /* The interrupt will be turned on when a link is established. */
+ NVIC_DisableIRQ( ETHERNET_IRQn );
+
+ /* Disable receive and transmit DMA processes. */
+ LPC_ETHERNET->DMA_OP_MODE &= ~( DMA_OM_ST | DMA_OM_SR );
+
+ /* Disable packet reception. */
+ LPC_ETHERNET->MAC_CONFIG &= ~( MAC_CFG_RE | MAC_CFG_TE );
+
+ /* Call the LPCOpen function to initialise the hardware. */
+ Chip_ENET_Init( LPC_ETHERNET );
+
+ /* Save MAC address. */
+ Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress );
+
+ /* Clear all MAC address hash entries. */
+ LPC_ETHERNET->MAC_HASHTABLE_HIGH = 0;
+ LPC_ETHERNET->MAC_HASHTABLE_LOW = 0;
+
+ #if( ipconfigUSE_LLMNR == 1 )
+ {
+ prvAddMACAddress( xLLMNR_MACAddress );
+ }
+ #endif /* ipconfigUSE_LLMNR == 1 */
+
+ /* Promiscuous flag (PR) and Receive All flag (RA) set to zero. The
+ registers MAC_HASHTABLE_[LOW|HIGH] will be loaded to allow certain
+ multi-cast addresses. */
+ LPC_ETHERNET->MAC_FRAME_FILTER = MAC_FF_HMC;
+
+ #if( configUSE_RMII == 1 )
+ {
+ if( lpc_phy_init( pdTRUE, prvDelay ) != SUCCESS )
+ {
+ xReturn = pdFAIL;
+ }
+ }
+ #else
+ {
+ #warning This path has not been tested.
+ if( lpc_phy_init( pdFALSE, prvDelay ) != SUCCESS )
+ {
+ xReturn = pdFAIL;
+ }
+ }
+ #endif
+
+ if( xReturn == pdPASS )
+ {
+ if( xTXDescriptorSemaphore == NULL )
+ {
+ /* Create a counting semaphore, with a value of 'configNUM_TX_DESCRIPTORS'
+ and a maximum of 'configNUM_TX_DESCRIPTORS'. */
+ xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) configNUM_TX_DESCRIPTORS, ( UBaseType_t ) configNUM_TX_DESCRIPTORS );
+ configASSERT( xTXDescriptorSemaphore );
+ }
+
+ /* Enable MAC interrupts. */
+ LPC_ETHERNET->DMA_INT_EN = nwDMA_INTERRUPT_MASK;
+
+ /* Auto-negotiate was already started. Wait for it to complete. */
+ xReturn = prvSetLinkSpeed();
+
+ if( xReturn == pdPASS )
+ {
+ /* Initialise the descriptors. */
+ prvSetupTxDescriptors();
+ prvSetupRxDescriptors();
+
+ /* Clear all interrupts. */
+ LPC_ETHERNET->DMA_STAT = DMA_ST_ALL;
+
+ /* Enable receive and transmit DMA processes. */
+ LPC_ETHERNET->DMA_OP_MODE |= DMA_OM_ST | DMA_OM_SR;
+
+ /* Set Receiver / Transmitter Enable. */
+ LPC_ETHERNET->MAC_CONFIG |= MAC_CFG_RE | MAC_CFG_TE;
+
+ /* Start receive polling. */
+ LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;
+
+ /* Enable interrupts in the NVIC. */
+ NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY );
+ NVIC_EnableIRQ( ETHERNET_IRQn );
+ }
+ /* Guard against the task being created more than once and the
+ descriptors being initialised more than once. */
+ if( xRxHanderTask == NULL )
+ {
+ xReturn = xTaskCreate( prvEMACHandlerTask, "EMAC", nwRX_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xRxHanderTask );
+ configASSERT( xReturn );
+ }
+ }
+ }
+
+ /* Once prvEMACHandlerTask() has started, the variable
+ 'ulPHYLinkStatus' will be updated by that task.
+ The IP-task will keep on calling this function untill
+ it finally returns pdPASS.
+ Only then can the DHCP-procedure start (if configured). */
+ if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 )
+ {
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+#define niBUFFER_1_PACKET_SIZE 1536
+
+static __attribute__ ((section("._ramAHB32"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );
+
+void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
+{
+
+uint8_t *ucRAMBuffer = ucNetworkPackets;
+uint32_t ul;
+
+ for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
+ {
+ pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
+ *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
+ ucRAMBuffer += niBUFFER_1_PACKET_SIZE;
+ }
+}
+/*-----------------------------------------------------------*/
+
+configPLACE_IN_SECTION_RAM
+static void vClearTXBuffers()
+{
+uint32_t ulLastDescriptor = ulNextFreeTxDescriptor;
+size_t uxCount = ( ( size_t ) configNUM_TX_DESCRIPTORS ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ NetworkBufferDescriptor_t *pxNetworkBuffer;
+ uint8_t *ucPayLoad;
+#endif
+
+ /* This function is called after a TX-completion interrupt.
+ It will release each Network Buffer used in xNetworkInterfaceOutput().
+ 'uxCount' represents the number of descriptors given to DMA for transmission.
+ After sending a packet, the DMA will clear the 'TDES_OWN' bit. */
+ while( ( uxCount > ( size_t ) 0u ) && ( ( xDMATxDescriptors[ ulTxDescriptorToClear ].CTRLSTAT & TDES_OWN ) == 0 ) )
+ {
+ if( ( ulTxDescriptorToClear == ulLastDescriptor ) && ( uxCount != ( size_t ) configNUM_TX_DESCRIPTORS ) )
+ {
+ break;
+ }
+
+
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ ucPayLoad = ( uint8_t * )xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD;
+ if( ucPayLoad != NULL )
+ {
+ /* B1ADD points to a pucEthernetBuffer of a Network Buffer descriptor. */
+ pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );
+
+ configASSERT( pxNetworkBuffer != NULL );
+
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;
+ xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD = ( uint32_t )0u;
+ }
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+ /* Move onto the next descriptor, wrapping if necessary. */
+ ulTxDescriptorToClear++;
+ if( ulTxDescriptorToClear >= configNUM_TX_DESCRIPTORS )
+ {
+ ulTxDescriptorToClear = 0;
+ }
+
+ uxCount--;
+ /* Tell the counting semaphore that one more TX descriptor is available. */
+ xSemaphoreGive( xTXDescriptorSemaphore );
+ }
+}
+
+/*-----------------------------------------------------------*/
+
+configPLACE_IN_SECTION_RAM
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
+{
+BaseType_t xReturn = pdFAIL;
+const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50 );
+
+ /* Attempt to obtain access to a Tx descriptor. */
+ do
+ {
+ if( xTXDescriptorSemaphore == NULL )
+ {
+ break;
+ }
+ if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
+ {
+ /* Time-out waiting for a free TX descriptor. */
+ break;
+ }
+
+ /* If the descriptor is still owned by the DMA it can't be used. */
+ if( ( xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT & TDES_OWN ) != 0 )
+ {
+ /* The semaphore was taken, the TX DMA-descriptor is still not available.
+ Actually that should not occur, the 'TDES_OWN' was already confirmed low in vClearTXBuffers(). */
+ xSemaphoreGive( xTXDescriptorSemaphore );
+ }
+ else
+ {
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* bReleaseAfterSend should always be set when using the zero
+ copy driver. */
+ configASSERT( bReleaseAfterSend != pdFALSE );
+
+ /* The DMA's descriptor to point directly to the data in the
+ network buffer descriptor. The data is not copied. */
+ xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD = ( uint32_t ) pxDescriptor->pucEthernetBuffer;
+
+ /* The DMA descriptor will 'own' this Network Buffer,
+ until it has been sent. So don't release it now. */
+ bReleaseAfterSend = pdFALSE;
+ }
+ #else
+ {
+ /* The data is copied from the network buffer descriptor into
+ the DMA's descriptor. */
+ memcpy( ( void * ) xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD, ( void * ) pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );
+ }
+ #endif
+
+ xDMATxDescriptors[ ulNextFreeTxDescriptor ].BSIZE = ( uint32_t ) TDES_ENH_BS1( pxDescriptor->xDataLength );
+
+ /* This descriptor is given back to the DMA. */
+ xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT |= TDES_OWN;
+
+ /* Ensure the DMA is polling Tx descriptors. */
+ LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;
+
+ iptraceNETWORK_INTERFACE_TRANSMIT();
+
+ /* Move onto the next descriptor, wrapping if necessary. */
+ ulNextFreeTxDescriptor++;
+ if( ulNextFreeTxDescriptor >= configNUM_TX_DESCRIPTORS )
+ {
+ ulNextFreeTxDescriptor = 0;
+ }
+
+ /* The Tx has been initiated. */
+ xReturn = pdPASS;
+ }
+ } while( 0 );
+
+ /* The buffer has been sent so can be released. */
+ if( bReleaseAfterSend != pdFALSE )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxDescriptor );
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static void prvDelay( uint32_t ulMilliSeconds )
+{
+ /* Ensure the scheduler was started before attempting to use the scheduler to
+ create a delay. */
+ configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING );
+
+ vTaskDelay( pdMS_TO_TICKS( ulMilliSeconds ) );
+}
+/*-----------------------------------------------------------*/
+
+static void prvSetupTxDescriptors( void )
+{
+BaseType_t x;
+
+ /* Start with Tx descriptors clear. */
+ memset( ( void * ) xDMATxDescriptors, 0, sizeof( xDMATxDescriptors ) );
+
+ /* Index to the next Tx descriptor to use. */
+ ulNextFreeTxDescriptor = 0ul;
+
+ /* Index to the next Tx descriptor to clear ( after transmission ). */
+ ulTxDescriptorToClear = 0ul;
+
+ for( x = 0; x < configNUM_TX_DESCRIPTORS; x++ )
+ {
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* Nothing to do, B1ADD will be set when data is ready to transmit.
+ Currently the memset above will have set it to NULL. */
+ }
+ #else
+ {
+ /* Allocate a buffer to the Tx descriptor. This is the most basic
+ way of creating a driver as the data is then copied into the
+ buffer. */
+ xDMATxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE );
+
+ /* Use an assert to check the allocation as +TCP applications will
+ often not use a malloc() failed hook as the TCP stack will recover
+ from allocation failures. */
+ configASSERT( xDMATxDescriptors[ x ].B1ADD );
+ }
+ #endif
+
+ /* Buffers hold an entire frame so all buffers are both the start and
+ end of a frame. */
+ /* TDES_ENH_TCH Second Address Chained. */
+ /* TDES_ENH_CIC(n) Checksum Insertion Control, tried but it does not work for the LPC18xx... */
+ /* TDES_ENH_FS First Segment. */
+ /* TDES_ENH_LS Last Segment. */
+ /* TDES_ENH_IC Interrupt on Completion. */
+ xDMATxDescriptors[ x ].CTRLSTAT = TDES_ENH_TCH | TDES_ENH_CIC( 3 ) | TDES_ENH_FS | TDES_ENH_LS | TDES_ENH_IC;
+ xDMATxDescriptors[ x ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ x + 1 ];
+ }
+
+ xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].CTRLSTAT |= TDES_ENH_TER;
+ xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ 0 ];
+
+ /* Point the DMA to the base of the descriptor list. */
+ LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xDMATxDescriptors;
+}
+/*-----------------------------------------------------------*/
+
+static void prvSetupRxDescriptors( void )
+{
+BaseType_t x;
+#if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+ NetworkBufferDescriptor_t *pxNetworkBuffer;
+#endif
+
+ /* Index to the next Rx descriptor to use. */
+ ulNextRxDescriptorToProcess = 0;
+
+ /* Clear RX descriptor list. */
+ memset( ( void * ) xDMARxDescriptors, 0, sizeof( xDMARxDescriptors ) );
+
+ for( x = 0; x < configNUM_RX_DESCRIPTORS; x++ )
+ {
+ /* Allocate a buffer of the largest possible frame size as it is not
+ known what size received frames will be. */
+
+ #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+ {
+ pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, 0 );
+
+ /* During start-up there should be enough Network Buffers available,
+ so it is safe to use configASSERT().
+ In case this assert fails, please check: configNUM_RX_DESCRIPTORS,
+ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, and in case BufferAllocation_2.c
+ is included, check the amount of available heap. */
+ configASSERT( pxNetworkBuffer != NULL );
+
+ /* Pass the actual buffer to DMA. */
+ xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer;
+ }
+ #else
+ {
+ /* All DMA descriptors are populated with permanent memory blocks.
+ Their contents will be copy to Network Buffers. */
+ xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE );
+ }
+ #endif /* ipconfigZERO_COPY_RX_DRIVER */
+
+ /* Use an assert to check the allocation as +TCP applications will often
+ not use a malloc failed hook as the TCP stack will recover from
+ allocation failures. */
+ configASSERT( xDMARxDescriptors[ x ].B1ADD );
+
+ xDMARxDescriptors[ x ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ x + 1 ] );
+ xDMARxDescriptors[ x ].CTRL = ( uint32_t ) RDES_ENH_BS1( ipTOTAL_ETHERNET_FRAME_SIZE ) | RDES_ENH_RCH;
+
+ /* The descriptor is available for use by the DMA. */
+ xDMARxDescriptors[ x ].STATUS = RDES_OWN;
+ }
+
+ /* RDES_ENH_RER Receive End of Ring. */
+ xDMARxDescriptors[ ( configNUM_RX_DESCRIPTORS - 1 ) ].CTRL |= RDES_ENH_RER;
+ xDMARxDescriptors[ configNUM_RX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ 0 ] );
+
+ /* Point the DMA to the base of the descriptor list. */
+ LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xDMARxDescriptors;
+}
+/*-----------------------------------------------------------*/
+configPLACE_IN_SECTION_RAM
+static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor )
+{
+size_t xExpectedLength;
+IPPacket_t *pxIPPacket;
+
+ pxIPPacket = ( IPPacket_t * ) pxDescriptor->pucEthernetBuffer;
+ /* Look at the actual length of the packet, translate it to a host-endial notation. */
+ xExpectedLength = sizeof( EthernetHeader_t ) + ( size_t ) FreeRTOS_htons( pxIPPacket->xIPHeader.usLength );
+
+ if( xExpectedLength == ( pxDescriptor->xDataLength + 4 ) )
+ {
+ pxDescriptor->xDataLength -= 4;
+ }
+ else
+ {
+ if( pxDescriptor->xDataLength > xExpectedLength )
+ {
+ pxDescriptor->xDataLength = ( size_t ) xExpectedLength;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+configPLACE_IN_SECTION_RAM
+BaseType_t xGetPhyLinkStatus( void )
+{
+BaseType_t xReturn;
+
+ if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 )
+ {
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+configPLACE_IN_SECTION_RAM
+static BaseType_t prvNetworkInterfaceInput()
+{
+BaseType_t xResult = pdFALSE;
+uint32_t ulStatus;
+eFrameProcessingResult_t eResult;
+const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );
+const UBaseType_t uxMinimumBuffersRemaining = 3UL;
+uint16_t usLength;
+NetworkBufferDescriptor_t *pxDescriptor;
+#if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+ NetworkBufferDescriptor_t *pxNewDescriptor;
+#endif /* ipconfigZERO_COPY_RX_DRIVER */
+IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
+
+ /* Process each descriptor that is not still in use by the DMA. */
+ ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS;
+ if( ( ulStatus & RDES_OWN ) == 0 )
+ {
+ /* Check packet for errors */
+ if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 )
+ {
+ /* There is some reception error. */
+ /* Clear error bits. */
+ ulStatus &= ~( ( uint32_t )nwRX_STATUS_ERROR_BITS );
+ }
+ else
+ {
+ xResult++;
+
+ eResult = ipCONSIDER_FRAME_FOR_PROCESSING( ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD ) );
+ if( eResult == eProcessBuffer )
+ {
+ if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 )
+ {
+ ulPHYLinkStatus |= PHY_LINK_CONNECTED;
+ FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (message received)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) );
+ }
+
+ #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+ if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining )
+ {
+ pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xDescriptorWaitTime );
+ }
+ else
+ {
+ /* Too risky to allocate a new Network Buffer. */
+ pxNewDescriptor = NULL;
+ }
+ if( pxNewDescriptor != NULL )
+ #else
+ if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining )
+ #endif /* ipconfigZERO_COPY_RX_DRIVER */
+ {
+ #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+ const uint8_t *pucBuffer;
+ #endif
+
+ /* Get the actual length. */
+ usLength = RDES_FLMSK( ulStatus );
+
+ #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+ {
+ /* Replace the character buffer 'B1ADD'. */
+ pucBuffer = ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD );
+ xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD = ( uint32_t ) pxNewDescriptor->pucEthernetBuffer;
+
+ /* 'B1ADD' contained the address of a 'pucEthernetBuffer' that
+ belongs to a Network Buffer. Find the original Network Buffer. */
+ pxDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
+ /* This zero-copy driver makes sure that every 'xDMARxDescriptors' contains
+ a reference to a Network Buffer at any time.
+ In case it runs out of Network Buffers, a DMA buffer won't be replaced,
+ and the received messages is dropped. */
+ configASSERT( pxDescriptor != NULL );
+ }
+ #else
+ {
+ /* Create a buffer of exactly the required length. */
+ pxDescriptor = pxGetNetworkBufferWithDescriptor( usLength, xDescriptorWaitTime );
+ }
+ #endif /* ipconfigZERO_COPY_RX_DRIVER */
+
+ if( pxDescriptor != NULL )
+ {
+ pxDescriptor->xDataLength = ( size_t ) usLength;
+ #if( ipconfigZERO_COPY_RX_DRIVER == 0 )
+ {
+ /* Copy the data into the allocated buffer. */
+ memcpy( ( void * ) pxDescriptor->pucEthernetBuffer, ( void * ) xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD, usLength );
+ }
+ #endif /* ipconfigZERO_COPY_RX_DRIVER */
+ /* It is possible that more data was copied than
+ actually makes up the frame. If this is the case
+ adjust the length to remove any trailing bytes. */
+ prvRemoveTrailingBytes( pxDescriptor );
+
+ /* Pass the data to the TCP/IP task for processing. */
+ xRxEvent.pvData = ( void * ) pxDescriptor;
+ if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE )
+ {
+ /* Could not send the descriptor into the TCP/IP
+ stack, it must be released. */
+ vReleaseNetworkBufferAndDescriptor( pxDescriptor );
+ }
+ else
+ {
+ iptraceNETWORK_INTERFACE_RECEIVE();
+ }
+ }
+ }
+ }
+ /* Got here because received data was sent to the IP task or the
+ data contained an error and was discarded. Give the descriptor
+ back to the DMA. */
+ xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS = ulStatus | RDES_OWN;
+
+ /* Move onto the next descriptor. */
+ ulNextRxDescriptorToProcess++;
+ if( ulNextRxDescriptorToProcess >= configNUM_RX_DESCRIPTORS )
+ {
+ ulNextRxDescriptorToProcess = 0;
+ }
+
+ ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS;
+ } /* if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 ) */
+ } /* if( ( ulStatus & RDES_OWN ) == 0 ) */
+
+ /* Restart receive polling. */
+ LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+configPLACE_IN_SECTION_RAM
+void NETWORK_IRQHandler( void )
+{
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+uint32_t ulDMAStatus;
+const uint32_t ulRxInterruptMask =
+ DMA_ST_RI | /* Receive interrupt */
+ DMA_ST_RU; /* Receive buffer unavailable */
+const uint32_t ulTxInterruptMask =
+ DMA_ST_TI | /* Transmit interrupt */
+ DMA_ST_TPS; /* Transmit process stopped */
+
+ configASSERT( xRxHanderTask );
+
+ /* Get pending interrupts. */
+ ulDMAStatus = LPC_ETHERNET->DMA_STAT;
+
+ /* RX group interrupt(s). */
+ if( ( ulDMAStatus & ulRxInterruptMask ) != 0x00 )
+ {
+ /* Remember that an RX event has happened. */
+ ulISREvents |= EMAC_IF_RX_EVENT;
+ vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );
+ }
+
+ /* TX group interrupt(s). */
+ if( ( ulDMAStatus & ulTxInterruptMask ) != 0x00 )
+ {
+ /* Remember that a TX event has happened. */
+ ulISREvents |= EMAC_IF_TX_EVENT;
+ vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );
+ }
+
+ /* Test for 'Abnormal interrupt summary'. */
+ if( ( ulDMAStatus & DMA_ST_AIE ) != 0x00 )
+ {
+ /* The trace macro must be written such that it can be called from
+ an interrupt. */
+ iptraceETHERNET_RX_EVENT_LOST();
+ }
+
+ /* Clear pending interrupts */
+ LPC_ETHERNET->DMA_STAT = ulDMAStatus;
+
+ /* Context switch needed? */
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvSetLinkSpeed( void )
+{
+BaseType_t xReturn = pdFAIL;
+TickType_t xTimeOnEntering;
+uint32_t ulPhyStatus;
+const TickType_t xAutoNegotiateDelay = pdMS_TO_TICKS( 5000UL );
+
+ /* Ensure polling does not starve lower priority tasks by temporarily
+ setting the priority of this task to that of the idle task. */
+ vTaskPrioritySet( NULL, tskIDLE_PRIORITY );
+
+ xTimeOnEntering = xTaskGetTickCount();
+ do
+ {
+ ulPhyStatus = lpcPHYStsPoll();
+ if( ( ulPhyStatus & PHY_LINK_CONNECTED ) != 0x00 )
+ {
+ /* Set interface speed and duplex. */
+ if( ( ulPhyStatus & PHY_LINK_SPEED100 ) != 0x00 )
+ {
+ Chip_ENET_SetSpeed( LPC_ETHERNET, 1 );
+ }
+ else
+ {
+ Chip_ENET_SetSpeed( LPC_ETHERNET, 0 );
+ }
+
+ if( ( ulPhyStatus & PHY_LINK_FULLDUPLX ) != 0x00 )
+ {
+ Chip_ENET_SetDuplex( LPC_ETHERNET, pdTRUE );
+ }
+ else
+ {
+ Chip_ENET_SetDuplex( LPC_ETHERNET, pdFALSE );
+ }
+
+ xReturn = pdPASS;
+ break;
+ }
+ } while( ( xTaskGetTickCount() - xTimeOnEntering ) < xAutoNegotiateDelay );
+
+ /* Reset the priority of this task back to its original value. */
+ vTaskPrioritySet( NULL, ipconfigIP_TASK_PRIORITY );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static uint32_t prvGenerateCRC32( const uint8_t *ucAddress )
+{
+unsigned int j;
+const uint32_t Polynomial = 0xEDB88320;
+uint32_t crc = ~0ul;
+const uint8_t *pucCurrent = ( const uint8_t * ) ucAddress;
+const uint8_t *pucLast = pucCurrent + 6;
+
+ /* Calculate normal CRC32 */
+ while( pucCurrent < pucLast )
+ {
+ crc ^= *( pucCurrent++ );
+ for( j = 0; j < 8; j++ )
+ {
+ if( ( crc & 1 ) != 0 )
+ {
+ crc = (crc >> 1) ^ Polynomial;
+ }
+ else
+ {
+ crc >>= 1;
+ }
+ }
+ }
+ return ~crc;
+}
+/*-----------------------------------------------------------*/
+
+static uint32_t prvGetHashIndex( const uint8_t *ucAddress )
+{
+uint32_t ulCrc = prvGenerateCRC32( ucAddress );
+uint32_t ulIndex = 0ul;
+BaseType_t xCount = 6;
+
+ /* Take the lowest 6 bits of the CRC32 and reverse them */
+ while( xCount-- )
+ {
+ ulIndex <<= 1;
+ ulIndex |= ( ulCrc & 1 );
+ ulCrc >>= 1;
+ }
+
+ /* This is the has value of 'ucAddress' */
+ return ulIndex;
+}
+/*-----------------------------------------------------------*/
+
+static void prvAddMACAddress( const uint8_t* ucMacAddress )
+{
+BaseType_t xIndex;
+
+ xIndex = prvGetHashIndex( ucMacAddress );
+ if( xIndex >= 32 )
+ {
+ LPC_ETHERNET->MAC_HASHTABLE_HIGH |= ( 1u << ( xIndex - 32 ) );
+ }
+ else
+ {
+ LPC_ETHERNET->MAC_HASHTABLE_LOW |= ( 1u << xIndex );
+ }
+}
+/*-----------------------------------------------------------*/
+
+configPLACE_IN_SECTION_RAM
+static void prvEMACHandlerTask( void *pvParameters )
+{
+TimeOut_t xPhyTime;
+TickType_t xPhyRemTime;
+UBaseType_t uxLastMinBufferCount = 0;
+UBaseType_t uxCurrentCount;
+BaseType_t xResult = 0;
+uint32_t ulStatus;
+const TickType_t xBlockTime = pdMS_TO_TICKS( 5000ul );
+
+ /* Remove compiler warning about unused parameter. */
+ ( void ) pvParameters;
+
+ /* A possibility to set some additional task properties. */
+ iptraceEMAC_TASK_STARTING();
+
+ vTaskSetTimeOutState( &xPhyTime );
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+
+ for( ;; )
+ {
+ uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
+ if( uxLastMinBufferCount != uxCurrentCount )
+ {
+ /* The logging produced below may be helpful
+ while tuning +TCP: see how many buffers are in use. */
+ uxLastMinBufferCount = uxCurrentCount;
+ FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
+ uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
+ }
+
+ #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+ {
+ static UBaseType_t uxLastMinQueueSpace = 0;
+
+ uxCurrentCount = uxGetMinimumIPQueueSpace();
+ if( uxLastMinQueueSpace != uxCurrentCount )
+ {
+ /* The logging produced below may be helpful
+ while tuning +TCP: see how many buffers are in use. */
+ uxLastMinQueueSpace = uxCurrentCount;
+ FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
+ }
+ }
+ #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
+
+ ulTaskNotifyTake( pdTRUE, xBlockTime );
+
+ xResult = ( BaseType_t ) 0;
+
+ if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
+ {
+ /* Code to release TX buffers if zero-copy is used. */
+ ulISREvents &= ~EMAC_IF_TX_EVENT;
+ {
+ /* Check if DMA packets have been delivered. */
+ vClearTXBuffers();
+ }
+ }
+
+ if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
+ {
+ ulISREvents &= ~EMAC_IF_RX_EVENT;
+
+ xResult = prvNetworkInterfaceInput();
+ if( xResult > 0 )
+ {
+ while( prvNetworkInterfaceInput() > 0 )
+ {
+ }
+ }
+ }
+
+ if( xResult > 0 )
+ {
+ /* A packet was received. No need to check for the PHY status now,
+ but set a timer to check it later on. */
+ vTaskSetTimeOutState( &xPhyTime );
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+ xResult = 0;
+ }
+ else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
+ {
+ ulStatus = lpcPHYStsPoll();
+
+ if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != ( ulStatus & PHY_LINK_CONNECTED ) )
+ {
+ ulPHYLinkStatus = ulStatus;
+ FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (polled PHY)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) );
+ }
+
+ vTaskSetTimeOutState( &xPhyTime );
+ if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 )
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+ }
+ else
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/ReadMe.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/ReadMe.txt
new file mode 100644
index 000000000..86a7f9121
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/ReadMe.txt
@@ -0,0 +1,3 @@
+NetworkInterface.c:
+Requires NXP's LPCOpen library and was developed on an LPC1830 and LPC1835 Xplorer
+boards from NGX. \ No newline at end of file
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/README_DRIVER_DISCLAIMER.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/README_DRIVER_DISCLAIMER.txt
new file mode 100644
index 000000000..347bb113e
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/README_DRIVER_DISCLAIMER.txt
@@ -0,0 +1,10 @@
+Network drivers are provided as examples only, and do not form part of the
+FreeRTOS+TCP stack itself. They:
+
+ + May be based on driver code provided by the chip vendors,
+ + May not have been tested in all possible configurations,
+ + Will not necessarily be optimised.
+ + May have a dependency on a particular PHY part number.
+ + May not necessarily comply with any particular coding standard.
+ + May have dependencies on chip company libraries.
+ + May include other hardware board dependencies.
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c
new file mode 100644
index 000000000..7c715a4eb
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c
@@ -0,0 +1,144 @@
+/*
+ * FreeRTOS+TCP Labs Build 150406 (C) 2015 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB: ***
+ *** ***
+ *** This product is functional and is already being used in commercial ***
+ *** products. Be aware however that we are still refining its design, ***
+ *** the source code does not yet fully conform to the strict coding and ***
+ *** style standards mandated by Real Time Engineers ltd., and the ***
+ *** documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * - Open source licensing -
+ * While FreeRTOS+TCP is in the lab it is provided only under version two of the
+ * GNU General Public License (GPL) (which is different to the standard FreeRTOS
+ * license). FreeRTOS+TCP is free to download, use and distribute under the
+ * terms of that license provided the copyright notice and this text are not
+ * altered or removed from the source files. The GPL V2 text is available on
+ * the gnu.org web site, and on the following
+ * URL: http://www.FreeRTOS.org/gpl-2.0.txt. Active early adopters may, and
+ * solely at the discretion of Real Time Engineers Ltd., be offered versions
+ * under a license other then the GPL.
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "NetworkBufferManagement.h"
+
+/* Hardware includes. */
+#include "hwEthernet.h"
+
+/* Demo includes. */
+#include "NetworkInterface.h"
+
+#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
+ #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
+#else
+ #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
+#endif
+
+/* When a packet is ready to be sent, if it cannot be sent immediately then the
+task performing the transmit will block for niTX_BUFFER_FREE_WAIT
+milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving
+up. */
+#define niTX_BUFFER_FREE_WAIT ( ( TickType_t ) 2UL / portTICK_PERIOD_MS )
+#define niMAX_TX_ATTEMPTS ( 5 )
+
+/* The length of the queue used to send interrupt status words from the
+interrupt handler to the deferred handler task. */
+#define niINTERRUPT_QUEUE_LENGTH ( 10 )
+
+/*-----------------------------------------------------------*/
+
+/*
+ * A deferred interrupt handler task that processes
+ */
+extern void vEMACHandlerTask( void *pvParameters );
+
+/*-----------------------------------------------------------*/
+
+/* The queue used to communicate Ethernet events with the IP task. */
+extern QueueHandle_t xNetworkEventQueue;
+
+/* The semaphore used to wake the deferred interrupt handler task when an Rx
+interrupt is received. */
+SemaphoreHandle_t xEMACRxEventSemaphore = NULL;
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceInitialise( void )
+{
+BaseType_t xStatus, xReturn;
+extern uint8_t ucMACAddress[ 6 ];
+
+ /* Initialise the MAC. */
+ vInitEmac();
+
+ while( lEMACWaitForLink() != pdPASS )
+ {
+ vTaskDelay( 20 );
+ }
+
+ vSemaphoreCreateBinary( xEMACRxEventSemaphore );
+ configASSERT( xEMACRxEventSemaphore );
+
+ /* The handler task is created at the highest possible priority to
+ ensure the interrupt handler can return directly to it. */
+ xTaskCreate( vEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
+ xReturn = pdPASS;
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer )
+{
+extern void vEMACCopyWrite( uint8_t * pucBuffer, uint16_t usLength );
+
+ vEMACCopyWrite( pxNetworkBuffer->pucBuffer, pxNetworkBuffer->xDataLength );
+
+ /* Finished with the network buffer. */
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+
+ return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c
new file mode 100644
index 000000000..d294fe92f
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c
@@ -0,0 +1,1458 @@
+/*
+ * Some constants, hardware definitions and comments taken from ST's HAL driver
+ * library, COPYRIGHT(c) 2015 STMicroelectronics.
+ */
+
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.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_DNS.h"
+#include "NetworkBufferManagement.h"
+#include "NetworkInterface.h"
+
+/* ST includes. */
+#include "stm32f4xx_hal.h"
+
+#ifndef BMSR_LINK_STATUS
+ #define BMSR_LINK_STATUS 0x0004UL
+#endif
+
+#ifndef PHY_LS_HIGH_CHECK_TIME_MS
+ /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
+ receiving packets. */
+ #define PHY_LS_HIGH_CHECK_TIME_MS 15000
+#endif
+
+#ifndef PHY_LS_LOW_CHECK_TIME_MS
+ /* Check if the LinkSStatus in the PHY is still low every second. */
+ #define PHY_LS_LOW_CHECK_TIME_MS 1000
+#endif
+
+/* Interrupt events to process. Currently only the Rx event is processed
+although code for other events is included to allow for possible future
+expansion. */
+#define EMAC_IF_RX_EVENT 1UL
+#define EMAC_IF_TX_EVENT 2UL
+#define EMAC_IF_ERR_EVENT 4UL
+#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
+
+#define ETH_DMA_ALL_INTS \
+ ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_ER | \
+ ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \
+ ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T )
+
+/* Naming and numbering of PHY registers. */
+#define PHY_REG_00_BMCR 0x00 /* Basic Mode Control Register. */
+#define PHY_REG_01_BMSR 0x01 /* Basic Mode Status Register. */
+#define PHY_REG_02_PHYSID1 0x02 /* PHYS ID 1 */
+#define PHY_REG_03_PHYSID2 0x03 /* PHYS ID 2 */
+#define PHY_REG_04_ADVERTISE 0x04 /* Advertisement control reg */
+
+#define PHY_ID_LAN8720 0x0007c0f0
+#define PHY_ID_DP83848I 0x20005C90
+
+#ifndef USE_STM324xG_EVAL
+ #define USE_STM324xG_EVAL 1
+#endif
+
+#if( USE_STM324xG_EVAL == 0 )
+ #define EXPECTED_PHY_ID PHY_ID_LAN8720
+ #define PHY_REG_1F_PHYSPCS 0x1F /* 31 RW PHY Special Control Status */
+ /* Use 3 bits in register 31 */
+ #define PHYSPCS_SPEED_MASK 0x0C
+ #define PHYSPCS_SPEED_10 0x04
+ #define PHYSPCS_SPEED_100 0x08
+ #define PHYSPCS_FULL_DUPLEX 0x10
+#else
+ #define EXPECTED_PHY_ID PHY_ID_DP83848I
+
+ #define PHY_REG_10_PHY_SR 0x10 /* PHY status register Offset */
+ #define PHY_REG_19_PHYCR 0x19 /* 25 RW PHY Control Register */
+#endif
+
+/* Some defines used internally here to indicate preferences about speed, MDIX
+(wired direct or crossed), and duplex (half or full). */
+#define PHY_SPEED_10 1
+#define PHY_SPEED_100 2
+#define PHY_SPEED_AUTO (PHY_SPEED_10|PHY_SPEED_100)
+
+#define PHY_MDIX_DIRECT 1
+#define PHY_MDIX_CROSSED 2
+#define PHY_MDIX_AUTO (PHY_MDIX_CROSSED|PHY_MDIX_DIRECT)
+
+#define PHY_DUPLEX_HALF 1
+#define PHY_DUPLEX_FULL 2
+#define PHY_DUPLEX_AUTO (PHY_DUPLEX_FULL|PHY_DUPLEX_HALF)
+
+#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
+
+/*
+ * Description of all capabilities that can be advertised to
+ * the peer (usually a switch or router).
+ */
+#define ADVERTISE_CSMA 0x0001 /* Only selector supported. */
+#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex. */
+#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex. */
+#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex. */
+#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex. */
+
+#define ADVERTISE_ALL ( ADVERTISE_10HALF | ADVERTISE_10FULL | \
+ ADVERTISE_100HALF | ADVERTISE_100FULL)
+
+/*
+ * Value for the 'PHY_REG_00_BMCR', the PHY's Basic Mode Control Register.
+ */
+#define BMCR_FULLDPLX 0x0100 /* Full duplex. */
+#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart. */
+#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation. */
+#define BMCR_SPEED100 0x2000 /* Select 100Mbps. */
+#define BMCR_RESET 0x8000 /* Reset the PHY. */
+
+#define PHYCR_MDIX_EN 0x8000 /* Enable Auto MDIX. */
+#define PHYCR_MDIX_FORCE 0x4000 /* Force MDIX crossed. */
+
+#define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */
+
+/*
+ * Most users will want a PHY that negotiates about
+ * the connection properties: speed, dmix and duplex.
+ * On some rare cases, you want to select what is being
+ * advertised, properties like MDIX and duplex.
+ */
+
+#if !defined( ipconfigETHERNET_AN_ENABLE )
+ /* Enable auto-negotiation */
+ #define ipconfigETHERNET_AN_ENABLE 1
+#endif
+
+#if !defined( ipconfigETHERNET_AUTO_CROSS_ENABLE )
+ #define ipconfigETHERNET_AUTO_CROSS_ENABLE 1
+#endif
+
+#if( ipconfigETHERNET_AN_ENABLE == 0 )
+ /*
+ * The following three defines are only used in case there
+ * is no auto-negotiation.
+ */
+ #if !defined( ipconfigETHERNET_CROSSED_LINK )
+ #define ipconfigETHERNET_CROSSED_LINK 1
+ #endif
+
+ #if !defined( ipconfigETHERNET_USE_100MB )
+ #define ipconfigETHERNET_USE_100MB 1
+ #endif
+
+ #if !defined( ipconfigETHERNET_USE_FULL_DUPLEX )
+ #define ipconfigETHERNET_USE_FULL_DUPLEX 1
+ #endif
+#endif /* ipconfigETHERNET_AN_ENABLE == 0 */
+
+/* Default the size of the stack used by the EMAC deferred handler task to twice
+the size of the stack used by the idle task - but allow this to be overridden in
+FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
+#ifndef configEMAC_TASK_STACK_SIZE
+ #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
+#endif
+
+/*-----------------------------------------------------------*/
+
+/*
+ * A deferred interrupt handler task that processes
+ */
+static void prvEMACHandlerTask( void *pvParameters );
+
+/*
+ * Force a negotiation with the Switch or Router and wait for LS.
+ */
+static void prvEthernetUpdateConfig( BaseType_t xForce );
+
+/*
+ * See if there is a new packet and forward it to the IP-task.
+ */
+static BaseType_t prvNetworkInterfaceInput( void );
+
+#if( ipconfigUSE_LLMNR != 0 )
+ /*
+ * For LLMNR, an extra MAC-address must be configured to
+ * be able to receive the multicast messages.
+ */
+ static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr);
+#endif
+
+/*
+ * Check if a given packet should be accepted.
+ */
+static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer );
+
+/*
+ * Initialise the TX descriptors.
+ */
+static void prvDMATxDescListInit( void );
+
+/*
+ * Initialise the RX descriptors.
+ */
+static void prvDMARxDescListInit( void );
+
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ /* After packets have been sent, the network
+ buffers will be released. */
+ static void vClearTXBuffers( void );
+#endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+/*-----------------------------------------------------------*/
+
+typedef struct _PhyProperties_t
+{
+ uint8_t speed;
+ uint8_t mdix;
+ uint8_t duplex;
+ uint8_t spare;
+} PhyProperties_t;
+
+/* Bit map of outstanding ETH interrupt events for processing. Currently only
+the Rx interrupt is handled, although code is included for other events to
+enable future expansion. */
+static volatile uint32_t ulISREvents;
+
+/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
+static uint32_t ulPHYLinkStatus = 0;
+
+#if( ipconfigUSE_LLMNR == 1 )
+ static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
+#endif
+
+/* Ethernet handle. */
+static ETH_HandleTypeDef xETH;
+
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ /* xTXDescriptorSemaphore is a counting semaphore with
+ a maximum count of ETH_TXBUFNB, which is the number of
+ DMA TX descriptors. */
+ static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
+#endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+/*
+ * Note: it is adviced to define both
+ *
+ * #define ipconfigZERO_COPY_RX_DRIVER 1
+ * #define ipconfigZERO_COPY_TX_DRIVER 1
+ *
+ * The method using memcpy is slower and probaly uses more RAM memory.
+ * The possibility is left in the code just for comparison.
+ *
+ * It is adviced to define ETH_TXBUFNB at least 4. Note that no
+ * TX buffers are allocated in a zero-copy driver.
+ */
+/* MAC buffers: ---------------------------------------------------------*/
+__ALIGN_BEGIN ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ] __ALIGN_END;/* Ethernet Rx MA Descriptor */
+#if( ipconfigZERO_COPY_RX_DRIVER == 0 )
+ __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END; /* Ethernet Receive Buffer */
+#endif
+
+__ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ] __ALIGN_END;/* Ethernet Tx DMA Descriptor */
+#if( ipconfigZERO_COPY_TX_DRIVER == 0 )
+ __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END; /* Ethernet Transmit Buffer */
+#endif
+
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ /* DMATxDescToClear points to the next TX DMA descriptor
+ that must be cleared by vClearTXBuffers(). */
+ static __IO ETH_DMADescTypeDef *DMATxDescToClear;
+#endif
+
+/* Value to be written into the 'Basic mode Control Register'. */
+static uint32_t ulBCRvalue;
+
+/* Value to be written into the 'Advertisement Control Register'. */
+static uint32_t ulACRValue;
+
+/* ucMACAddress as it appears in main.c */
+extern const uint8_t ucMACAddress[ 6 ];
+
+/* Holds the handle of the task used as a deferred interrupt processor. The
+handle is used so direct notifications can be sent to the task for all EMAC/DMA
+related interrupts. */
+static TaskHandle_t xEMACTaskHandle = NULL;
+
+/* For local use only: describe the PHY's properties: */
+const PhyProperties_t xPHYProperties =
+{
+ #if( ipconfigETHERNET_AN_ENABLE != 0 )
+ .speed = PHY_SPEED_AUTO,
+ .duplex = PHY_DUPLEX_AUTO,
+ #else
+ #if( ipconfigETHERNET_USE_100MB != 0 )
+ .speed = PHY_SPEED_100,
+ #else
+ .speed = PHY_SPEED_10,
+ #endif
+
+ #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )
+ .duplex = PHY_DUPLEX_FULL,
+ #else
+ .duplex = PHY_DUPLEX_HALF,
+ #endif
+ #endif
+
+ #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 )
+ .mdix = PHY_MDIX_AUTO,
+ #elif( ipconfigETHERNET_CROSSED_LINK != 0 )
+ .mdix = PHY_MDIX_CROSSED,
+ #else
+ .mdix = PHY_MDIX_DIRECT,
+ #endif
+};
+
+/*-----------------------------------------------------------*/
+
+void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth )
+{
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+
+ /* Ethernet RX-Complete callback function, elsewhere declared as weak. */
+ ulISREvents |= EMAC_IF_RX_EVENT;
+ /* Wakeup the prvEMACHandlerTask. */
+ if( xEMACTaskHandle != NULL )
+ {
+ vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+ }
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth )
+ {
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+
+ /* This call-back is only useful in case packets are being sent
+ zero-copy. Once they're sent, the buffers will be released
+ by the function vClearTXBuffers(). */
+ ulISREvents |= EMAC_IF_TX_EVENT;
+ /* Wakeup the prvEMACHandlerTask. */
+ if( xEMACTaskHandle != NULL )
+ {
+ vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+ }
+
+ }
+#endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+/*-----------------------------------------------------------*/
+
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ static void vClearTXBuffers()
+ {
+ __IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc;
+ NetworkBufferDescriptor_t *pxNetworkBuffer;
+ uint8_t *ucPayLoad;
+ size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
+
+ /* This function is called after a TX-completion interrupt.
+ It will release each Network Buffer used in xNetworkInterfaceOutput().
+ 'uxCount' represents the number of descriptors given to DMA for transmission.
+ After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */
+ while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) )
+ {
+ if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) )
+ {
+ break;
+ }
+
+ ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr;
+
+ if( ucPayLoad != NULL )
+ {
+ pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );
+ if( pxNetworkBuffer != NULL )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;
+ }
+ DMATxDescToClear->Buffer1Addr = ( uint32_t )0u;
+ }
+
+ DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr );
+
+ uxCount--;
+ /* Tell the counting semaphore that one more TX descriptor is available. */
+ xSemaphoreGive( xTXDescriptorSemaphore );
+ }
+ }
+#endif /* ipconfigZERO_COPY_TX_DRIVER */
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceInitialise( void )
+{
+HAL_StatusTypeDef hal_eth_init_status;
+BaseType_t xResult;
+
+ if( xEMACTaskHandle == NULL )
+ {
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ if( xTXDescriptorSemaphore == NULL )
+ {
+ xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB );
+ configASSERT( xTXDescriptorSemaphore );
+ }
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+ /* Initialise ETH */
+
+ xETH.Instance = ETH;
+ xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
+ xETH.Init.Speed = ETH_SPEED_100M;
+ xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
+ xETH.Init.PhyAddress = 1;
+
+ xETH.Init.MACAddr = ( uint8_t *) ucMACAddress;
+ xETH.Init.RxMode = ETH_RXINTERRUPT_MODE;
+
+ /* using the ETH_CHECKSUM_BY_HARDWARE option:
+ both the IP and the protocol checksums will be calculated
+ by the peripheral. */
+ xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
+
+ xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII;
+ hal_eth_init_status = HAL_ETH_Init( &xETH );
+
+ /* Only for inspection by debugger. */
+ ( void ) hal_eth_init_status;
+
+ /* Set the TxDesc and RxDesc pointers. */
+ xETH.TxDesc = DMATxDscrTab;
+ xETH.RxDesc = DMARxDscrTab;
+
+ /* Make sure that all unused fields are cleared. */
+ memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) );
+ memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) );
+
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* Initialize Tx Descriptors list: Chain Mode */
+ DMATxDescToClear = DMATxDscrTab;
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+ /* Initialise TX-descriptors. */
+ prvDMATxDescListInit();
+
+ /* Initialise RX-descriptors. */
+ prvDMARxDescListInit();
+
+ #if( ipconfigUSE_LLMNR != 0 )
+ {
+ /* Program the LLMNR address at index 1. */
+ prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress );
+ }
+ #endif
+
+ /* Force a negotiation with the Switch or Router and wait for LS. */
+ prvEthernetUpdateConfig( pdTRUE );
+
+ /* The deferred interrupt handler task is created at the highest
+ possible priority to ensure the interrupt handler can return directly
+ to it. The task's handle is stored in xEMACTaskHandle so interrupts can
+ notify the task when there is something to process. */
+ xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
+ } /* if( xEMACTaskHandle == NULL ) */
+
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS;
+ xResult = pdPASS;
+ FreeRTOS_printf( ( "Link Status is high\n" ) ) ;
+ }
+ else
+ {
+ /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
+ and it will keep on checking the PHY and set ulPHYLinkStatus when necessary. */
+ xResult = pdFAIL;
+ FreeRTOS_printf( ( "Link Status still low\n" ) ) ;
+ }
+ /* When returning non-zero, the stack will become active and
+ start DHCP (in configured) */
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+static void prvDMATxDescListInit()
+{
+ETH_DMADescTypeDef *pxDMADescriptor;
+BaseType_t xIndex;
+
+ /* Get the pointer on the first member of the descriptor list */
+ pxDMADescriptor = DMATxDscrTab;
+
+ /* Fill each DMA descriptor with the right values */
+ for( xIndex = 0; xIndex < ETH_TXBUFNB; xIndex++, pxDMADescriptor++ )
+ {
+ /* Set Second Address Chained bit */
+ pxDMADescriptor->Status = ETH_DMATXDESC_TCH;
+
+ #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
+ {
+ /* Set Buffer1 address pointer */
+ pxDMADescriptor->Buffer1Addr = ( uint32_t )( Tx_Buff[ xIndex ] );
+ }
+ #endif
+
+ if( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE )
+ {
+ /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */
+ pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;
+ }
+
+ /* Initialize the next descriptor with the Next Descriptor Polling Enable */
+ if( xIndex < ETH_TXBUFNB - 1 )
+ {
+ /* Set next descriptor address register with next descriptor base address */
+ pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 );
+ }
+ else
+ {
+ /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
+ pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMATxDscrTab;
+ }
+ }
+
+ /* Set Transmit Descriptor List Address Register */
+ xETH.Instance->DMATDLAR = ( uint32_t ) DMATxDscrTab;
+}
+/*-----------------------------------------------------------*/
+
+static void prvDMARxDescListInit()
+{
+ETH_DMADescTypeDef *pxDMADescriptor;
+BaseType_t xIndex;
+ /*
+ * RX-descriptors.
+ */
+
+ /* Get the pointer on the first member of the descriptor list */
+ pxDMADescriptor = DMARxDscrTab;
+
+ /* Fill each DMA descriptor with the right values */
+ for( xIndex = 0; xIndex < ETH_RXBUFNB; xIndex++, pxDMADescriptor++ )
+ {
+
+ /* Set Buffer1 size and Second Address Chained bit */
+ pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;
+
+ #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+ {
+ /* Set Buffer1 address pointer */
+ NetworkBufferDescriptor_t *pxBuffer;
+
+ pxBuffer = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, 100ul );
+ /* If the assert below fails, make sure that there are at least 'ETH_RXBUFNB'
+ Network Buffers available during start-up ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) */
+ configASSERT( pxBuffer != NULL );
+ if( pxBuffer != NULL )
+ {
+ pxDMADescriptor->Buffer1Addr = (uint32_t)pxBuffer->pucEthernetBuffer;
+ pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
+ }
+ }
+ #else
+ {
+ /* Set Buffer1 address pointer */
+ pxDMADescriptor->Buffer1Addr = ( uint32_t )( Rx_Buff[ xIndex ] );
+ /* Set Own bit of the Rx descriptor Status */
+ pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
+ }
+ #endif
+
+ /* Initialize the next descriptor with the Next Descriptor Polling Enable */
+ if( xIndex < ETH_RXBUFNB - 1 )
+ {
+ /* Set next descriptor address register with next descriptor base address */
+ pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t )( pxDMADescriptor + 1 );
+ }
+ else
+ {
+ /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
+ pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMARxDscrTab;
+ }
+
+ }
+ /* Set Receive Descriptor List Address Register */
+ xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab;
+}
+/*-----------------------------------------------------------*/
+
+static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr)
+{
+uint32_t ulTempReg;
+
+ /* Calculate the selected MAC address high register. */
+ ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ];
+
+ /* Load the selected MAC address high register. */
+ ( *(__IO uint32_t *)( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg;
+
+ /* Calculate the selected MAC address low register. */
+ ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ];
+
+ /* Load the selected MAC address low register */
+ ( *(__IO uint32_t *) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
+{
+BaseType_t xReturn = pdFAIL;
+uint32_t ulTransmitSize = 0;
+__IO ETH_DMADescTypeDef *pxDmaTxDesc;
+/* Do not wait too long for a free TX DMA buffer. */
+const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
+
+ #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
+ {
+ ProtocolPacket_t *pxPacket;
+
+ /* If the peripheral must calculate the checksum, it wants
+ the protocol checksum to have a value of zero. */
+ pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer );
+
+ if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP )
+ {
+ pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u;
+ }
+ }
+ #endif
+
+ /* Open a do {} while ( 0 ) loop to be able to call break. */
+ do
+ {
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ if( xTXDescriptorSemaphore == NULL )
+ {
+ break;
+ }
+ if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
+ {
+ /* Time-out waiting for a free TX descriptor. */
+ break;
+ }
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+ /* This function does the actual transmission of the packet. The packet is
+ contained in 'pxDescriptor' that is passed to the function. */
+ pxDmaTxDesc = xETH.TxDesc;
+
+ /* Is this buffer available? */
+ if( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 )
+ {
+ /* Is this buffer available? */
+ /* Get bytes in current buffer. */
+ ulTransmitSize = pxDescriptor->xDataLength;
+
+ if( ulTransmitSize > ETH_TX_BUF_SIZE )
+ {
+ ulTransmitSize = ETH_TX_BUF_SIZE;
+ }
+
+ #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
+ {
+ /* Copy the bytes. */
+ memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize );
+ pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL;
+ }
+ #else
+ {
+ /* Move the buffer. */
+ pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer;
+ /* Ask to set the IPv4 checksum.
+ Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */
+ pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC;
+ /* The Network Buffer has been passed to DMA, no need to release it. */
+ bReleaseAfterSend = pdFALSE_UNSIGNED;
+ }
+ #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+ /* Prepare transmit descriptors to give to DMA. */
+
+ /* Set LAST and FIRST segment */
+ pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS;
+ /* Set frame size */
+ pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 );
+ /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
+ pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN;
+
+ /* Point to next descriptor */
+ xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr );
+
+ /* Resume DMA transmission*/
+ xETH.Instance->DMATPDR = 0;
+ iptraceNETWORK_INTERFACE_TRANSMIT();
+ xReturn = pdPASS;
+ }
+ }
+ else
+ {
+ /* The PHY has no Link Status, packet shall be dropped. */
+ }
+ } while( 0 );
+ /* The buffer has been sent so can be released. */
+ if( bReleaseAfterSend != pdFALSE )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxDescriptor );
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer )
+{
+const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer;
+
+ switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType )
+ {
+ case ipARP_FRAME_TYPE:
+ /* Check it later. */
+ return pdTRUE;
+ case ipIPv4_FRAME_TYPE:
+ /* Check it here. */
+ break;
+ default:
+ /* Refuse the packet. */
+ return pdFALSE;
+ }
+
+ #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
+ {
+ const IPHeader_t *pxIPHeader = &(pxProtPacket->xTCPPacket.xIPHeader);
+ uint32_t 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 & FreeRTOS_ntohs( ipFRAGMENT_OFFSET_BIT_MASK ) ) != 0U )
+ {
+ return pdFALSE;
+ }
+ /* HT: Might want to make the following configurable because
+ * most IP messages have a standard length of 20 bytes */
+
+ /* 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 */
+ if( pxIPHeader->ucVersionHeaderLength < 0x45 || pxIPHeader->ucVersionHeaderLength > 0x4F )
+ {
+ return pdFALSE;
+ }
+
+ ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;
+ /* Is the packet for this node? */
+ if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&
+ /* Is it a broadcast address x.x.x.255 ? */
+ ( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xff ) != 0xff ) &&
+ #if( ipconfigUSE_LLMNR == 1 )
+ ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&
+ #endif
+ ( *ipLOCAL_IP_ADDRESS_POINTER != 0 ) ) {
+ FreeRTOS_printf( ( "Drop IP %lxip\n", FreeRTOS_ntohl( ulDestinationIPAddress ) ) );
+ return pdFALSE;
+ }
+
+ if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP )
+ {
+ uint16_t port = pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort;
+
+ if( ( xPortHasUDPSocket( port ) == pdFALSE )
+ #if ipconfigUSE_LLMNR == 1
+ && ( port != FreeRTOS_ntohs( ipLLMNR_PORT ) )
+ #endif
+ #if ipconfigUSE_NBNS == 1
+ && ( port != FreeRTOS_ntohs( ipNBNS_PORT ) )
+ #endif
+ #if ipconfigUSE_DNS == 1
+ && ( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort != FreeRTOS_ntohs( ipDNS_PORT ) )
+ #endif
+ ) {
+ /* Drop this packet, not for this device. */
+ return pdFALSE;
+ }
+ }
+ }
+ #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
+ return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvNetworkInterfaceInput( void )
+{
+NetworkBufferDescriptor_t *pxCurDescriptor;
+NetworkBufferDescriptor_t *pxNewDescriptor = NULL;
+BaseType_t xReceivedLength, xAccepted;
+__IO ETH_DMADescTypeDef *pxDMARxDescriptor;
+xIPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
+const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );
+uint8_t *pucBuffer;
+
+ pxDMARxDescriptor = xETH.RxDesc;
+
+ if( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN) == 0 )
+ {
+ /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
+ xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4;
+
+ pucBuffer = (uint8_t *) pxDMARxDescriptor->Buffer1Addr;
+
+ /* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */
+ /* Chained Mode */
+ /* Selects the next DMA Rx descriptor list for next buffer to read */
+ xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr;
+ }
+ else
+ {
+ xReceivedLength = 0;
+ }
+
+ /* Obtain the size of the packet and put it into the "usReceivedLength" variable. */
+
+ /* get received frame */
+ if( xReceivedLength > 0ul )
+ {
+ /* In order to make the code easier and faster, only packets in a single buffer
+ will be accepted. This can be done by making the buffers large enough to
+ hold a complete Ethernet packet (1536 bytes).
+ Therefore, two sanity checks: */
+ configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE );
+
+ if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT )
+ {
+ /* Not an Ethernet frame-type or a checmsum error. */
+ xAccepted = pdFALSE;
+ }
+ else
+ {
+ /* See if this packet must be handled. */
+ xAccepted = xMayAcceptPacket( pucBuffer );
+ }
+
+ if( xAccepted != pdFALSE )
+ {
+ /* The packet wil be accepted, but check first if a new Network Buffer can
+ be obtained. If not, the packet will still be dropped. */
+ pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, xDescriptorWaitTime );
+
+ if( pxNewDescriptor == NULL )
+ {
+ /* A new descriptor can not be allocated now. This packet will be dropped. */
+ xAccepted = pdFALSE;
+ }
+ }
+ #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+ {
+ /* Find out which Network Buffer was originally passed to the descriptor. */
+ pxCurDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
+ configASSERT( pxCurDescriptor != NULL );
+ }
+ #else
+ {
+ /* In this mode, the two descriptors are the same. */
+ pxCurDescriptor = pxNewDescriptor;
+ if( pxNewDescriptor != NULL )
+ {
+ /* The packet is acepted and a new Network Buffer was created,
+ copy data to the Network Bufffer. */
+ memcpy( pxNewDescriptor->pucEthernetBuffer, pucBuffer, xReceivedLength );
+ }
+ }
+ #endif
+
+ if( xAccepted != pdFALSE )
+ {
+ pxCurDescriptor->xDataLength = xReceivedLength;
+ xRxEvent.pvData = ( void * ) pxCurDescriptor;
+
+ /* Pass the data to the TCP/IP task for processing. */
+ if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE )
+ {
+ /* Could not send the descriptor into the TCP/IP stack, it
+ must be released. */
+ vReleaseNetworkBufferAndDescriptor( pxCurDescriptor );
+ iptraceETHERNET_RX_EVENT_LOST();
+ }
+ else
+ {
+ iptraceNETWORK_INTERFACE_RECEIVE();
+ }
+ }
+
+ /* Release descriptors to DMA */
+ #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
+ {
+ /* Set Buffer1 address pointer */
+ if( pxNewDescriptor != NULL )
+ {
+ pxDMARxDescriptor->Buffer1Addr = (uint32_t)pxNewDescriptor->pucEthernetBuffer;
+ }
+ else
+ {
+ /* The packet was dropped and the same Network
+ Buffer will be used to receive a new packet. */
+ }
+ }
+ #endif /* ipconfigZERO_COPY_RX_DRIVER */
+
+ /* Set Buffer1 size and Second Address Chained bit */
+ pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;
+ pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN;
+
+ /* When Rx Buffer unavailable flag is set clear it and resume
+ reception. */
+ if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 )
+ {
+ /* Clear RBUS ETHERNET DMA flag. */
+ xETH.Instance->DMASR = ETH_DMASR_RBUS;
+
+ /* Resume DMA reception. */
+ xETH.Instance->DMARPDR = 0;
+ }
+ }
+
+ return ( xReceivedLength > 0 );
+}
+/*-----------------------------------------------------------*/
+
+void vMACBProbePhy( void )
+{
+uint32_t ulConfig, ulAdvertise, ulLower, ulUpper, ulMACPhyID, ulValue;
+TimeOut_t xPhyTime;
+TickType_t xRemTime = 0;
+#if( EXPECTED_PHY_ID == PHY_ID_DP83848I )
+ uint32_t ulPhyControl;
+#endif
+
+ HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_03_PHYSID2, &ulLower);
+ HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_02_PHYSID1, &ulUpper);
+
+ ulMACPhyID = ( ( ulUpper << 16 ) & 0xFFFF0000 ) | ( ulLower & 0xFFF0 );
+
+ /* The expected ID for the 'LAN8720' is 0x0007c0f0. */
+ /* The expected ID for the 'DP83848I' is 0x20005C90. */
+
+ FreeRTOS_printf( ( "PHY ID %lX (%s)\n", ulMACPhyID,
+ ( ulMACPhyID == EXPECTED_PHY_ID ) ? "OK" : "Unknown" ) );
+
+ /* Remove compiler warning if FreeRTOS_printf() is not defined. */
+ ( void ) ulMACPhyID;
+
+ /* Set advertise register. */
+ if( ( xPHYProperties.speed == PHY_SPEED_AUTO ) && ( xPHYProperties.duplex == PHY_DUPLEX_AUTO ) )
+ {
+ ulAdvertise = ADVERTISE_CSMA | ADVERTISE_ALL;
+ /* Reset auto-negotiation capability. */
+ }
+ else
+ {
+ ulAdvertise = ADVERTISE_CSMA;
+
+ if( xPHYProperties.speed == PHY_SPEED_AUTO )
+ {
+ if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
+ {
+ ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_100FULL;
+ }
+ else
+ {
+ ulAdvertise |= ADVERTISE_10HALF | ADVERTISE_100HALF;
+ }
+ }
+ else if( xPHYProperties.duplex == PHY_DUPLEX_AUTO )
+ {
+ if( xPHYProperties.speed == PHY_SPEED_10 )
+ {
+ ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_10HALF;
+ }
+ else
+ {
+ ulAdvertise |= ADVERTISE_100FULL | ADVERTISE_100HALF;
+ }
+ }
+ else if( xPHYProperties.speed == PHY_SPEED_100 )
+ {
+ if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
+ {
+ ulAdvertise |= ADVERTISE_100FULL;
+ }
+ else
+ {
+ ulAdvertise |= ADVERTISE_100HALF;
+ }
+ }
+ else
+ {
+ if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
+ {
+ ulAdvertise |= ADVERTISE_10FULL;
+ }
+ else
+ {
+ ulAdvertise |= ADVERTISE_10HALF;
+ }
+ }
+ }
+
+ /* Read Control register. */
+ HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig );
+
+ HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig | BMCR_RESET );
+ xRemTime = ( TickType_t ) pdMS_TO_TICKS( 1000UL );
+ vTaskSetTimeOutState( &xPhyTime );
+
+ for( ; ; )
+ {
+ HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulValue );
+ if( ( ulValue & BMCR_RESET ) == 0 )
+ {
+ FreeRTOS_printf( ( "BMCR_RESET ready\n" ) );
+ break;
+ }
+ if( xTaskCheckForTimeOut( &xPhyTime, &xRemTime ) != pdFALSE )
+ {
+ FreeRTOS_printf( ( "BMCR_RESET timed out\n" ) );
+ break;
+ }
+ }
+ HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig & ~BMCR_RESET );
+
+ vTaskDelay( pdMS_TO_TICKS( 50ul ) );
+
+ /* Write advertise register. */
+ HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulAdvertise );
+
+ /*
+ AN_EN AN1 AN0 Forced Mode
+ 0 0 0 10BASE-T, Half-Duplex
+ 0 0 1 10BASE-T, Full-Duplex
+ 0 1 0 100BASE-TX, Half-Duplex
+ 0 1 1 100BASE-TX, Full-Duplex
+ AN_EN AN1 AN0 Advertised Mode
+ 1 0 0 10BASE-T, Half/Full-Duplex
+ 1 0 1 100BASE-TX, Half/Full-Duplex
+ 1 1 0 10BASE-T Half-Duplex
+ 100BASE-TX, Half-Duplex
+ 1 1 1 10BASE-T, Half/Full-Duplex
+ 100BASE-TX, Half/Full-Duplex
+ */
+
+ /* Read Control register. */
+ HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig );
+
+ ulConfig &= ~( BMCR_ANRESTART | BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX );
+
+ /* HT 12/9/14: always set AN-restart and AN-enable, even though the choices
+ are limited. */
+ ulConfig |= (BMCR_ANRESTART | BMCR_ANENABLE);
+
+ if( xPHYProperties.speed == PHY_SPEED_100 )
+ {
+ ulConfig |= BMCR_SPEED100;
+ }
+ else if( xPHYProperties.speed == PHY_SPEED_10 )
+ {
+ ulConfig &= ~BMCR_SPEED100;
+ }
+
+ if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
+ {
+ ulConfig |= BMCR_FULLDPLX;
+ }
+ else if( xPHYProperties.duplex == PHY_DUPLEX_HALF )
+ {
+ ulConfig &= ~BMCR_FULLDPLX;
+ }
+
+ #if( EXPECTED_PHY_ID == PHY_ID_LAN8720 )
+ {
+ }
+ #elif( EXPECTED_PHY_ID == PHY_ID_DP83848I )
+ {
+ /* Read PHY Control register. */
+ HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_19_PHYCR, &ulPhyControl );
+
+ /* Clear bits which might get set: */
+ ulPhyControl &= ~( PHYCR_MDIX_EN|PHYCR_MDIX_FORCE );
+
+ if( xPHYProperties.mdix == PHY_MDIX_AUTO )
+ {
+ ulPhyControl |= PHYCR_MDIX_EN;
+ }
+ else if( xPHYProperties.mdix == PHY_MDIX_CROSSED )
+ {
+ /* Force direct link = Use crossed RJ45 cable. */
+ ulPhyControl &= ~PHYCR_MDIX_FORCE;
+ }
+ else
+ {
+ /* Force crossed link = Use direct RJ45 cable. */
+ ulPhyControl |= PHYCR_MDIX_FORCE;
+ }
+ /* update PHY Control Register. */
+ HAL_ETH_WritePHYRegister( &xETH, PHY_REG_19_PHYCR, ulPhyControl );
+ }
+ #endif
+ FreeRTOS_printf( ( "+TCP: advertise: %lX config %lX\n", ulAdvertise, ulConfig ) );
+
+ /* Now the two values to global values for later use. */
+ ulBCRvalue = ulConfig;
+ ulACRValue = ulAdvertise;
+}
+/*-----------------------------------------------------------*/
+
+static void prvEthernetUpdateConfig( BaseType_t xForce )
+{
+__IO uint32_t ulTimeout = 0;
+uint32_t ulRegValue = 0;
+
+ FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS %d Force %d\n",
+ ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ,
+ xForce ) );
+
+ if( ( xForce != pdFALSE ) || ( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) )
+ {
+ /* Restart the auto-negotiation. */
+ if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE )
+ {
+ /* Enable Auto-Negotiation. */
+ HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue | BMCR_ANRESTART );
+ HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulACRValue);
+
+ /* Wait until the auto-negotiation will be completed */
+ do
+ {
+ ulTimeout++;
+ HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue );
+ } while( ( ( ulRegValue & PHY_AUTONEGO_COMPLETE) == 0 ) && ( ulTimeout < PHY_READ_TO ) );
+
+ HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue & ~BMCR_ANRESTART );
+
+ if( ulTimeout < PHY_READ_TO )
+ {
+ /* Reset Timeout counter. */
+ ulTimeout = 0;
+
+ HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue);
+ if( ( ulRegValue & BMSR_LINK_STATUS ) != 0 )
+ {
+ ulPHYLinkStatus |= BMSR_LINK_STATUS;
+ }
+ else
+ {
+ ulPHYLinkStatus &= ~( BMSR_LINK_STATUS );
+ }
+
+ #if( EXPECTED_PHY_ID == PHY_ID_LAN8720 )
+ {
+ /* 31 RW PHY Special Control Status */
+ uint32_t ulControlStatus;
+
+ HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_1F_PHYSPCS, &ulControlStatus);
+ ulRegValue = 0;
+ if( ( ulControlStatus & PHYSPCS_FULL_DUPLEX ) != 0 )
+ {
+ ulRegValue |= PHY_DUPLEX_STATUS;
+ }
+ if( ( ulControlStatus & PHYSPCS_SPEED_MASK ) == PHYSPCS_SPEED_10 )
+ {
+ ulRegValue |= PHY_SPEED_STATUS;
+ }
+
+ }
+ #elif( EXPECTED_PHY_ID == PHY_ID_DP83848I )
+ {
+ /* Read the result of the auto-negotiation. */
+ HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_10_PHY_SR, &ulRegValue);
+ }
+ #endif
+ FreeRTOS_printf( ( ">> Autonego ready: %08lx: %s duplex %u mbit %s status\n",
+ ulRegValue,
+ (ulRegValue & PHY_DUPLEX_STATUS) ? "full" : "half",
+ (ulRegValue & PHY_SPEED_STATUS) ? 10 : 100,
+ ((ulPHYLinkStatus |= BMSR_LINK_STATUS) != 0) ? "high" : "low" ) );
+
+ /* Configure the MAC with the Duplex Mode fixed by the
+ auto-negotiation process. */
+ if( ( ulRegValue & PHY_DUPLEX_STATUS ) != ( uint32_t ) RESET )
+ {
+ /* Set Ethernet duplex mode to Full-duplex following the
+ auto-negotiation. */
+ xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
+ }
+ else
+ {
+ /* Set Ethernet duplex mode to Half-duplex following the
+ auto-negotiation. */
+ xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
+ }
+
+ /* Configure the MAC with the speed fixed by the
+ auto-negotiation process. */
+ if( ( ulRegValue & PHY_SPEED_STATUS) != 0 )
+ {
+ /* Set Ethernet speed to 10M following the
+ auto-negotiation. */
+ xETH.Init.Speed = ETH_SPEED_10M;
+ }
+ else
+ {
+ /* Set Ethernet speed to 100M following the
+ auto-negotiation. */
+ xETH.Init.Speed = ETH_SPEED_100M;
+ }
+ } /* if( ulTimeout < PHY_READ_TO ) */
+ }
+ else /* AutoNegotiation Disable */
+ {
+ uint16_t usValue;
+
+ /* Check parameters */
+ assert_param( IS_ETH_SPEED( xETH.Init.Speed ) );
+ assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) );
+
+ /* Set MAC Speed and Duplex Mode to PHY */
+ usValue = ( uint16_t ) ( xETH.Init.DuplexMode >> 3 ) | ( uint16_t ) ( xETH.Init.Speed >> 1 );
+ HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, usValue );
+ }
+
+ /* ETHERNET MAC Re-Configuration */
+ HAL_ETH_ConfigMAC( &xETH, (ETH_MACInitTypeDef *) NULL);
+
+ /* Restart MAC interface */
+ HAL_ETH_Start( &xETH);
+ }
+ else
+ {
+ /* Stop MAC interface */
+ HAL_ETH_Stop( &xETH );
+ }
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xGetPhyLinkStatus( void )
+{
+BaseType_t xReturn;
+
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static void prvEMACHandlerTask( void *pvParameters )
+{
+TimeOut_t xPhyTime;
+TickType_t xPhyRemTime;
+UBaseType_t uxLastMinBufferCount = 0;
+#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+UBaseType_t uxLastMinQueueSpace = 0;
+#endif
+UBaseType_t uxCurrentCount;
+BaseType_t xResult = 0;
+uint32_t xStatus;
+const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
+
+ /* Remove compiler warnings about unused parameters. */
+ ( void ) pvParameters;
+
+ vTaskSetTimeOutState( &xPhyTime );
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+
+ for( ;; )
+ {
+ uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
+ if( uxLastMinBufferCount != uxCurrentCount )
+ {
+ /* The logging produced below may be helpful
+ while tuning +TCP: see how many buffers are in use. */
+ uxLastMinBufferCount = uxCurrentCount;
+ FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
+ uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
+ }
+
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ if( xTXDescriptorSemaphore != NULL )
+ {
+ static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1;
+
+ uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );
+ if( uxLowestSemCount > uxCurrentCount )
+ {
+ uxLowestSemCount = uxCurrentCount;
+ FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) );
+ }
+
+ }
+ #endif
+ #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+ {
+ uxCurrentCount = uxGetMinimumIPQueueSpace();
+ if( uxLastMinQueueSpace != uxCurrentCount )
+ {
+ /* The logging produced below may be helpful
+ while tuning +TCP: see how many buffers are in use. */
+ uxLastMinQueueSpace = uxCurrentCount;
+ FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
+ }
+ }
+ #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
+
+ if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
+ {
+ /* No events to process now, wait for the next. */
+ ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
+ }
+
+ if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
+ {
+ ulISREvents &= ~EMAC_IF_RX_EVENT;
+
+ xResult = prvNetworkInterfaceInput();
+ if( xResult > 0 )
+ {
+ while( prvNetworkInterfaceInput() > 0 )
+ {
+ }
+ }
+ }
+
+ if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
+ {
+ /* Code to release TX buffers if zero-copy is used. */
+ ulISREvents &= ~EMAC_IF_TX_EVENT;
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* Check if DMA packets have been delivered. */
+ vClearTXBuffers();
+ }
+ #endif
+ }
+
+ if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
+ {
+ /* Future extension: logging about errors that occurred. */
+ ulISREvents &= ~EMAC_IF_ERR_EVENT;
+ }
+
+ if( xResult > 0 )
+ {
+ /* A packet was received. No need to check for the PHY status now,
+ but set a timer to check it later on. */
+ vTaskSetTimeOutState( &xPhyTime );
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+ xResult = 0;
+ }
+ else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
+ {
+ HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &xStatus );
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
+ {
+ ulPHYLinkStatus = xStatus;
+ FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
+ prvEthernetUpdateConfig( pdFALSE );
+ }
+
+ vTaskSetTimeOutState( &xPhyTime );
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+ }
+ else
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+void ETH_IRQHandler( void )
+{
+ HAL_ETH_IRQHandler( &xETH );
+}
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c
new file mode 100644
index 000000000..e100a4e97
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c
@@ -0,0 +1,173 @@
+#define xBUFFER_CACHE_SIZE 10
+#define xMAX_FAULT_INJECTION_RATE 15
+#define xMIN_FAULT_INJECTION_RATE 3
+#define xNUM_FAULT_TYPES 1
+
+static NetworkBufferDescriptor_t *xNetworkBufferCache[ xBUFFER_CACHE_SIZE ] = { 0 };
+
+#define xFAULT_LOG_SIZE 2048
+uint32_t ulInjectedFault[ xFAULT_LOG_SIZE ];
+uint32_t ulFaultLogIndex = 0;
+
+static BaseType_t prvCachePacket( NetworkBufferDescriptor_t *pxNetworkBufferIn )
+{
+BaseType_t x, xReturn = pdFALSE;
+
+ for( x = 0; x < xBUFFER_CACHE_SIZE; x++ )
+ {
+ if( xNetworkBufferCache[ x ] == NULL )
+ {
+ xNetworkBufferCache[ x ] = pxNetworkBufferIn;
+ xReturn = pdTRUE;
+ break;
+ }
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static NetworkBufferDescriptor_t *prvGetCachedPacket( void )
+{
+BaseType_t x;
+NetworkBufferDescriptor_t *pxReturn = NULL;
+
+ for( x = ( xBUFFER_CACHE_SIZE - 1 ); x >= 0; x-- )
+ {
+ if( xNetworkBufferCache[ x ] != NULL )
+ {
+ pxReturn = xNetworkBufferCache[ x ];
+ xNetworkBufferCache[ x ] = NULL;
+ break;
+ }
+ }
+
+ return pxReturn;
+}
+/*-----------------------------------------------------------*/
+
+static NetworkBufferDescriptor_t *prvDuplicatePacket( NetworkBufferDescriptor_t * pxOriginalPacket, const uint8_t *pucPacketData )
+{
+NetworkBufferDescriptor_t *pxReturn;
+
+ /* Obtain a new descriptor. */
+ pxReturn = pxGetNetworkBufferWithDescriptor( pxOriginalPacket->xDataLength, 0 );
+
+ if( pxReturn != NULL )
+ {
+ /* Copy in the packet data. */
+ pxReturn->xDataLength = pxOriginalPacket->xDataLength;
+ memcpy( pxReturn->pucEthernetBuffer, pucPacketData, pxOriginalPacket->xDataLength );
+ }
+
+ return pxReturn;
+}
+/*-----------------------------------------------------------*/
+
+static NetworkBufferDescriptor_t *prvRxFaultInjection( NetworkBufferDescriptor_t *pxNetworkBufferIn, const uint8_t *pucPacketData )
+{
+static uint32_t ulCallCount = 0, ulNextFaultCallCount = 0;
+NetworkBufferDescriptor_t *pxReturn = pxNetworkBufferIn;
+IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
+uint32_t ulFault;
+
+return pxNetworkBufferIn;
+
+ ulCallCount++;
+
+ if( ulCallCount > ulNextFaultCallCount )
+ {
+ ulNextFaultCallCount = ipconfigRAND32() % xMAX_FAULT_INJECTION_RATE;
+ if( ulNextFaultCallCount < xMIN_FAULT_INJECTION_RATE )
+ {
+ ulNextFaultCallCount = xMIN_FAULT_INJECTION_RATE;
+ }
+
+ ulCallCount = 0;
+
+ ulFault = ipconfigRAND32() % xNUM_FAULT_TYPES;
+
+ if( ulFaultLogIndex < xFAULT_LOG_SIZE )
+ {
+ ulInjectedFault[ ulFaultLogIndex ] = ulFault;
+ ulFaultLogIndex++;
+ }
+
+ switch( ulFault )
+ {
+ case 0:
+ /* Just drop the packet. */
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn );
+ pxReturn = NULL;
+ break;
+
+ case 1:
+ /* Store the packet in the cache for later. */
+ if( prvCachePacket( pxNetworkBufferIn ) == pdTRUE )
+ {
+ /* The packet may get sent later, it is not being sent
+ now. */
+ pxReturn = NULL;
+ }
+ break;
+
+ case 2:
+ /* Send a cached packet. */
+ pxReturn = prvGetCachedPacket();
+ if( pxReturn != NULL )
+ {
+ /* A cached packet was obtained so drop the original
+ packet. */
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn );
+ }
+ else
+ {
+ /* Could not obtain a packet from the cache so just return
+ the packet that was passed in. */
+ pxReturn = pxNetworkBufferIn;
+ }
+ break;
+
+ case 4:
+
+ /* Send a duplicate of the packet right away. */
+ pxReturn = prvDuplicatePacket( pxNetworkBufferIn, pucPacketData );
+
+ /* Send the original packet to the stack. */
+ xRxEvent.pvData = ( void * ) pxNetworkBufferIn;
+ if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn );
+ }
+ break;
+
+ case 5:
+
+ /* Send both a cached packet and the current packet. */
+ xRxEvent.pvData = ( void * ) prvGetCachedPacket();
+ if( xRxEvent.pvData != NULL )
+ {
+ if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn );
+ }
+ }
+ break;
+
+ case 6:
+ case 7:
+ case 8:
+ /* Store the packet in the cache for later. */
+ if( prvCachePacket( pxNetworkBufferIn ) == pdTRUE )
+ {
+ /* The packet may get sent later, it is not being sent
+ now. */
+ pxReturn = NULL;
+ }
+ break;
+ }
+ }
+
+ return pxReturn;
+}
+/*-----------------------------------------------------------*/
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c
new file mode 100644
index 000000000..1d92adee7
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c
@@ -0,0 +1,631 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* WinPCap includes. */
+#define HAVE_REMOTE
+#include "pcap.h"
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_IP_Private.h"
+#include "NetworkBufferManagement.h"
+
+/* Thread-safe circular buffers are being used to pass data to and from the PCAP
+access functions. */
+#include "Win32-Extensions.h"
+#include "FreeRTOS_Stream_Buffer.h"
+
+/* Sizes of the thread safe circular buffers used to pass data to and from the
+WinPCAP Windows threads. */
+#define xSEND_BUFFER_SIZE 32768
+#define xRECV_BUFFER_SIZE 32768
+
+/* 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. */
+#if( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
+ #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
+#else
+ #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
+#endif
+
+/* Used to insert test code only. */
+#define niDISRUPT_PACKETS 0
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Windows threads that are outside of the control of the FreeRTOS simulator are
+ * used to interface with the WinPCAP libraries.
+ */
+DWORD WINAPI prvWinPcapRecvThread( void *pvParam );
+DWORD WINAPI prvWinPcapSendThread( void *pvParam );
+
+/*
+ * Print out a numbered list of network interfaces that are available on the
+ * host computer.
+ */
+static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );
+
+/*
+ * Open the network interface. The number of the interface to be opened is set
+ * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
+ */
+static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces );
+static void prvOpenInterface( const char *pucName );
+
+/*
+ * Configure the capture filter to allow blocking reads, and to filter out
+ * packets that are not of interest to this demo.
+ */
+static void prvConfigureCaptureBehaviour( void );
+
+/*
+ * A function that simulates Ethernet interrupts by periodically polling the
+ * WinPCap interface for new data.
+ */
+static void prvInterruptSimulatorTask( void *pvParameters );
+
+/*
+ * Create the buffers that are used to pass data between the FreeRTOS simulator
+ * and the Win32 threads that manage WinPCAP.
+ */
+static void prvCreateThreadSafeBuffers( void );
+
+/*
+ * Utility function used to format print messages only.
+ */
+static const char *prvRemoveSpaces( char *pcBuffer, int aBuflen, const char *pcMessage );
+
+/*-----------------------------------------------------------*/
+
+/* Required by the WinPCap library. */
+static char cErrorBuffer[ PCAP_ERRBUF_SIZE ];
+
+/* An event used to wake up the Win32 thread that sends data through the WinPCAP
+library. */
+static void *pvSendEvent = NULL;
+
+/* _HT_ made the PCAP interface number configurable through the program's
+parameters in order to test in different machines. */
+static BaseType_t xConfigNextworkInterfaceToUse = configNETWORK_INTERFACE_TO_USE;
+
+/* Handles to the Windows threads that handle the PCAP IO. */
+static HANDLE vWinPcapRecvThreadHandle = NULL;
+static HANDLE vWinPcapSendThreadHandle = NULL;;
+
+/* The interface being used by WinPCap. */
+static pcap_t *pxOpenedInterfaceHandle = NULL;
+
+/* Circular buffers used by the PCAP Win32 threads. */
+static StreamBuffer_t *xSendBuffer = NULL;
+static StreamBuffer_t *xRecvBuffer = NULL;
+
+/* The MAC address initially set to the constants defined in FreeRTOSConfig.h. */
+extern uint8_t ucMACAddress[ 6 ];
+
+/* Logs the number of WinPCAP send failures, for viewing in the debugger only. */
+static volatile uint32_t ulWinPCAPSendFailures = 0;
+
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceInitialise( void )
+{
+BaseType_t xReturn = pdFALSE;
+pcap_if_t *pxAllNetworkInterfaces;
+
+ /* Query the computer the simulation is being executed on to find the
+ network interfaces it has installed. */
+ pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();
+
+ /* Open the network interface. The number of the interface to be opened is
+ set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
+ Calling this function will set the pxOpenedInterfaceHandle variable. If,
+ after calling this function, pxOpenedInterfaceHandle is equal to NULL, then
+ the interface could not be opened. */
+ if( pxAllNetworkInterfaces != NULL )
+ {
+ prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );
+ }
+
+ if( pxOpenedInterfaceHandle != NULL )
+ {
+ xReturn = pdPASS;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static void prvCreateThreadSafeBuffers( void )
+{
+ /* The buffer used to pass data to be transmitted from a FreeRTOS task to
+ the Win32 thread that sends via the WinPCAP library. */
+ if( xSendBuffer == NULL)
+ {
+ xSendBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) + xSEND_BUFFER_SIZE + 1 );
+ configASSERT( xSendBuffer );
+ memset( xSendBuffer, '\0', sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) );
+ xSendBuffer->LENGTH = xSEND_BUFFER_SIZE + 1;
+ }
+
+ /* The buffer used to pass received data from the Win32 thread that receives
+ via the WinPCAP library to the FreeRTOS task. */
+ if( xRecvBuffer == NULL)
+ {
+ xRecvBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) + xRECV_BUFFER_SIZE + 1 );
+ configASSERT( xRecvBuffer );
+ memset( xRecvBuffer, '\0', sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) );
+ xRecvBuffer->LENGTH = xRECV_BUFFER_SIZE + 1;
+ }
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t bReleaseAfterSend )
+{
+size_t xSpace;
+
+ iptraceNETWORK_INTERFACE_TRANSMIT();
+ configASSERT( xIsCallingFromIPTask() == pdTRUE );
+
+ /* Both the length of the data being sent and the actual data being sent
+ are placed in the thread safe buffer used to pass data between the FreeRTOS
+ tasks and the Win32 thread that sends data via the WinPCAP library. Drop
+ the packet if there is insufficient space in the buffer to hold both. */
+ xSpace = uxStreamBufferGetSpace( xSendBuffer );
+
+ if( ( pxNetworkBuffer->xDataLength <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) &&
+ ( xSpace >= ( pxNetworkBuffer->xDataLength + sizeof( pxNetworkBuffer->xDataLength ) ) ) )
+ {
+ /* First write in the length of the data, then write in the data
+ itself. */
+ uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) &( pxNetworkBuffer->xDataLength ), sizeof( pxNetworkBuffer->xDataLength ) );
+ uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
+ }
+ else
+ {
+ FreeRTOS_debug_printf( ( "xNetworkInterfaceOutput: send buffers full to store %lu\n", pxNetworkBuffer->xDataLength ) );
+ }
+
+ /* Kick the Tx task in either case in case it doesn't know the buffer is
+ full. */
+ SetEvent( pvSendEvent );
+
+ /* The buffer has been sent so can be released. */
+ if( bReleaseAfterSend != pdFALSE )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ }
+
+ return pdPASS;
+}
+/*-----------------------------------------------------------*/
+
+static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )
+{
+pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface;
+int32_t lInterfaceNumber = 1;
+char cBuffer[ 512 ];
+
+ if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )
+ {
+ printf( "Could not obtain a list of network interfaces\n%s\n", cErrorBuffer );
+ pxAllNetworkInterfaces = NULL;
+ }
+
+ if( pxAllNetworkInterfaces != NULL )
+ {
+ /* Print out the list of network interfaces. The first in the list
+ is interface '1', not interface '0'. */
+ for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )
+ {
+ /* The descriptions of the devices can be full of spaces, clean them
+ a little. printf() can only be used here because the network is not
+ up yet - so no other network tasks will be running. */
+ printf( "%d. %s\n", lInterfaceNumber, prvRemoveSpaces( cBuffer, sizeof( cBuffer ), xInterface->name ) );
+ printf( " (%s)\n", prvRemoveSpaces(cBuffer, sizeof( cBuffer ), xInterface->description ? xInterface->description : "No description" ) );
+ printf( "\n" );
+ lInterfaceNumber++;
+ }
+ }
+
+ if( lInterfaceNumber == 1 )
+ {
+ /* The interface number was never incremented, so the above for() loop
+ did not execute meaning no interfaces were found. */
+ printf( " \nNo network interfaces were found.\n" );
+ pxAllNetworkInterfaces = NULL;
+ }
+
+ printf( "The interface that will be opened is set by\n" );
+ printf( "\"configNETWORK_INTERFACE_TO_USE\" which should be defined in FreeRTOSConfig.h\n" );
+ printf( "Attempting to open interface number %d.\n", xConfigNextworkInterfaceToUse );
+
+ if( ( xConfigNextworkInterfaceToUse < 1L ) || ( xConfigNextworkInterfaceToUse > lInterfaceNumber ) )
+ {
+ printf( "configNETWORK_INTERFACE_TO_USE is not in the valid range.\n" );
+
+ if( pxAllNetworkInterfaces != NULL )
+ {
+ /* Free the device list, as no devices are going to be opened. */
+ pcap_freealldevs( pxAllNetworkInterfaces );
+ pxAllNetworkInterfaces = NULL;
+ }
+ }
+
+ return pxAllNetworkInterfaces;
+}
+/*-----------------------------------------------------------*/
+
+static void prvOpenInterface( const char *pucName )
+{
+static char pucInterfaceName[ 256 ];
+
+ if( pucName != NULL )
+ {
+ strncpy( pucInterfaceName, pucName, sizeof( pucInterfaceName ) );
+ }
+
+ pxOpenedInterfaceHandle = pcap_open( pucInterfaceName, /* The name of the selected interface. */
+ ipTOTAL_ETHERNET_FRAME_SIZE, /* The size of the packet to capture. */
+ PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscuous mode as the MAC and
+ IP address is going to be "simulated", and
+ not be the real MAC and IP address. This allows
+ traffic to the simulated IP address to be routed
+ to uIP, and traffic to the real IP address to be
+ routed to the Windows TCP/IP stack. */
+ 100,
+ NULL, /* No authentication is required as this is
+ not a remote capture session. */
+ cErrorBuffer
+ );
+
+ if ( pxOpenedInterfaceHandle == NULL )
+ {
+ printf( "\n%s is not supported by WinPcap and cannot be opened\n", pucInterfaceName );
+ }
+ else
+ {
+ /* Configure the capture filter to allow blocking reads, and to filter
+ out packets that are not of interest to this demo. */
+ prvConfigureCaptureBehaviour();
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces )
+{
+pcap_if_t *xInterface;
+int32_t x;
+
+ /* Walk the list of devices until the selected device is located. */
+ xInterface = pxAllNetworkInterfaces;
+ for( x = 0L; x < ( xConfigNextworkInterfaceToUse - 1L ); x++ )
+ {
+ xInterface = xInterface->next;
+ }
+
+ /* Open the selected interface. */
+ prvOpenInterface( xInterface->name );
+
+ /* The device list is no longer required. */
+ pcap_freealldevs( pxAllNetworkInterfaces );
+}
+/*-----------------------------------------------------------*/
+
+static void prvConfigureCaptureBehaviour( void )
+{
+struct bpf_program xFilterCode;
+uint32_t ulNetMask;
+
+ /* Set up a filter so only the packets of interest are passed to the IP
+ stack. cErrorBuffer is used for convenience to create the string. Don't
+ confuse this with an error message. */
+ sprintf( cErrorBuffer, "broadcast or multicast or ether host %x:%x:%x:%x:%x:%x",
+ ucMACAddress[0], ucMACAddress[1], ucMACAddress[2], ucMACAddress[3], ucMACAddress[4], ucMACAddress[5] );
+
+ ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;
+
+ if( pcap_compile( pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )
+ {
+ printf( "\nThe packet filter string is invalid\n" );
+ }
+ else
+ {
+ if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )
+ {
+ printf( "\nAn error occurred setting the packet filter.\n" );
+ }
+ }
+
+ /* Create the buffers used to pass packets between the FreeRTOS simulator
+ and the Win32 threads that are handling WinPCAP. */
+ prvCreateThreadSafeBuffers();
+
+ if( pvSendEvent == NULL )
+ {
+ /* Create event used to signal the Win32 WinPCAP Tx thread. */
+ pvSendEvent = CreateEvent( NULL, FALSE, TRUE, NULL );
+
+ /* Create the Win32 thread that handles WinPCAP Rx. */
+ vWinPcapRecvThreadHandle = CreateThread(
+ NULL, /* Pointer to thread security attributes. */
+ 0, /* Initial thread stack size, in bytes. */
+ prvWinPcapRecvThread, /* Pointer to thread function. */
+ NULL, /* Argument for new thread. */
+ 0, /* Creation flags. */
+ NULL );
+
+ /* Use the cores that are not used by the FreeRTOS tasks. */
+ SetThreadAffinityMask( vWinPcapRecvThreadHandle, ~0x01u );
+
+ /* Create the Win32 thread that handlers WinPCAP Tx. */
+ vWinPcapSendThreadHandle = CreateThread(
+ NULL, /* Pointer to thread security attributes. */
+ 0, /* initial thread stack size, in bytes. */
+ prvWinPcapSendThread, /* Pointer to thread function. */
+ NULL, /* Argument for new thread. */
+ 0, /* Creation flags. */
+ NULL );
+
+ /* Use the cores that are not used by the FreeRTOS tasks. */
+ SetThreadAffinityMask( vWinPcapSendThreadHandle, ~0x01u );
+
+ /* Create a task that simulates an interrupt in a real system. This will
+ block waiting for packets, then send a message to the IP task when data
+ is available. */
+ xTaskCreate( prvInterruptSimulatorTask, "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, configMAC_ISR_SIMULATOR_PRIORITY, NULL );
+ }
+}
+/*-----------------------------------------------------------*/
+
+/* WinPCAP function. */
+void pcap_callback( u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data )
+{
+ (void)user;
+
+ /* THIS IS CALLED FROM A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS
+ OR TO PRINT OUT MESSAGES HERE. */
+
+ /* Pass data to the FreeRTOS simulator on a thread safe circular buffer. */
+ if( ( pkt_header->caplen <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) &&
+ ( uxStreamBufferGetSpace( xRecvBuffer ) >= ( ( ( size_t ) pkt_header->caplen ) + sizeof( *pkt_header ) ) ) )
+ {
+ uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t* ) pkt_header, sizeof( *pkt_header ) );
+ uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t* ) pkt_data, ( size_t ) pkt_header->caplen );
+ }
+}
+/*-----------------------------------------------------------*/
+
+DWORD WINAPI prvWinPcapRecvThread ( void *pvParam )
+{
+ ( void ) pvParam;
+
+ /* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS OR TO PRINT
+ OUT MESSAGES HERE. */
+
+ for( ;; )
+ {
+ pcap_dispatch( pxOpenedInterfaceHandle, 1, pcap_callback, ( u_char * ) "mydata" );
+ }
+}
+/*-----------------------------------------------------------*/
+
+DWORD WINAPI prvWinPcapSendThread( void *pvParam )
+{
+size_t xLength;
+uint8_t ucBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ];
+static char cErrorMessage[ 1024 ];
+const DWORD xMaxMSToWait = 1000;
+
+ /* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS OR TO PRINT
+ OUT MESSAGES HERE. */
+
+ /* Remove compiler warnings about unused parameters. */
+ ( void ) pvParam;
+
+ for( ;; )
+ {
+ /* Wait until notified of something to send. */
+ WaitForSingleObject( pvSendEvent, xMaxMSToWait );
+
+ /* Is there more than the length value stored in the circular buffer
+ used to pass data from the FreeRTOS simulator into this Win32 thread? */
+ while( uxStreamBufferGetSize( xSendBuffer ) > sizeof( xLength ) )
+ {
+ uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE );
+ uxStreamBufferGet( xSendBuffer, 0, ( uint8_t* ) ucBuffer, xLength, pdFALSE );
+ if( pcap_sendpacket( pxOpenedInterfaceHandle, ucBuffer, xLength ) != 0 )
+ {
+ ulWinPCAPSendFailures++;
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvInterruptSimulatorTask( void *pvParameters )
+{
+struct pcap_pkthdr xHeader;
+static struct pcap_pkthdr *pxHeader;
+const uint8_t *pucPacketData;
+uint8_t ucRecvBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ];
+NetworkBufferDescriptor_t *pxNetworkBuffer;
+IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
+eFrameProcessingResult_t eResult;
+
+ /* Remove compiler warnings about unused parameters. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* Does the circular buffer used to pass data from the Win32 thread that
+ handles WinPCAP Rx into the FreeRTOS simulator contain another packet? */
+ if( uxStreamBufferGetSize( xRecvBuffer ) > sizeof( xHeader ) )
+ {
+ /* Get the next packet. */
+ uxStreamBufferGet( xRecvBuffer, 0, (uint8_t*)&xHeader, sizeof( xHeader ), pdFALSE );
+ uxStreamBufferGet( xRecvBuffer, 0, (uint8_t*)ucRecvBuffer, ( size_t ) xHeader.len, pdFALSE );
+ pucPacketData = ucRecvBuffer;
+ pxHeader = &xHeader;
+
+ iptraceNETWORK_INTERFACE_RECEIVE();
+
+ eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData );
+ if( eResult == eProcessBuffer )
+ {
+ /* Will the data fit into the frame buffer? */
+ if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE )
+ {
+ /* Obtain a buffer into which the data can be placed. This
+ is only an interrupt simulator, not a real interrupt, so it
+ is ok to call the task level function here, but note that
+ some buffer implementations cannot be called from a real
+ interrupt. */
+ pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( pxHeader->len, 0 );
+
+ if( pxNetworkBuffer != NULL )
+ {
+ memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len );
+ pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len;
+
+ #if( niDISRUPT_PACKETS == 1 )
+ {
+ pxNetworkBuffer = vRxFaultInjection( pxNetworkBuffer, pucPacketData );
+ }
+ #endif /* niDISRUPT_PACKETS */
+
+ if( pxNetworkBuffer != NULL )
+ {
+ xRxEvent.pvData = ( void * ) pxNetworkBuffer;
+
+ /* Data was received and stored. Send a message to
+ the IP task to let it know. */
+ if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
+ {
+ /* The buffer could not be sent to the stack so
+ must be released again. This is only an
+ interrupt simulator, not a real interrupt, so it
+ is ok to use the task level function here, but
+ note no all buffer implementations will allow
+ this function to be executed from a real
+ interrupt. */
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ iptraceETHERNET_RX_EVENT_LOST();
+ }
+ }
+ else
+ {
+ /* The packet was already released or stored inside
+ vRxFaultInjection(). Don't release it here. */
+ }
+ }
+ else
+ {
+ iptraceETHERNET_RX_EVENT_LOST();
+ }
+ }
+ else
+ {
+ /* Log that a packet was dropped because it would have
+ overflowed the buffer, but there may be more buffers to
+ process. */
+ }
+ }
+ }
+ else
+ {
+ /* There is no real way of simulating an interrupt. Make sure
+ other tasks can run. */
+ vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY );
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static const char *prvRemoveSpaces( char *pcBuffer, int aBuflen, const char *pcMessage )
+{
+ char *pcTarget = pcBuffer;
+
+ /* Utility function used to formap messages being printed only. */
+ while( ( *pcMessage != 0 ) && ( pcTarget < ( pcBuffer + aBuflen - 1 ) ) )
+ {
+ *( pcTarget++ ) = *pcMessage;
+
+ if( isspace( *pcMessage ) != pdFALSE )
+ {
+ while( isspace( *pcMessage ) != pdFALSE )
+ {
+ pcMessage++;
+ }
+ }
+ else
+ {
+ pcMessage++;
+ }
+ }
+
+ *pcTarget = '\0';
+
+ return pcBuffer;
+}
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c
new file mode 100644
index 000000000..6cbda2745
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c
@@ -0,0 +1,430 @@
+/*
+ * FreeRTOS+TCP Labs Build 200417 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.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 "NetworkBufferManagement.h"
+#include "NetworkInterface.h"
+
+/* Xilinx library files. */
+#include <xemacps.h>
+#include "Zynq/x_topology.h"
+#include "Zynq/x_emacpsif.h"
+#include "Zynq/x_emacpsif_hw.h"
+
+/* Provided memory configured as uncached. */
+#include "uncached_memory.h"
+
+#ifndef BMSR_LINK_STATUS
+ #define BMSR_LINK_STATUS 0x0004UL
+#endif
+
+#ifndef PHY_LS_HIGH_CHECK_TIME_MS
+ /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
+ receiving packets. */
+ #define PHY_LS_HIGH_CHECK_TIME_MS 15000
+#endif
+
+#ifndef PHY_LS_LOW_CHECK_TIME_MS
+ /* Check if the LinkSStatus in the PHY is still low every second. */
+ #define PHY_LS_LOW_CHECK_TIME_MS 1000
+#endif
+
+/* The size of each buffer when BufferAllocation_1 is used:
+http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html */
+#define niBUFFER_1_PACKET_SIZE 1536
+
+/* Naming and numbering of PHY registers. */
+#define PHY_REG_01_BMSR 0x01 /* Basic mode status register */
+
+#ifndef iptraceEMAC_TASK_STARTING
+ #define iptraceEMAC_TASK_STARTING() do { } while( 0 )
+#endif
+
+/* Default the size of the stack used by the EMAC deferred handler task to twice
+the size of the stack used by the idle task - but allow this to be overridden in
+FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
+#ifndef configEMAC_TASK_STACK_SIZE
+ #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
+#endif
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Look for the link to be up every few milliseconds until either xMaxTime time
+ * has passed or a link is found.
+ */
+static BaseType_t prvGMACWaitLS( TickType_t xMaxTime );
+
+/*
+ * A deferred interrupt handler for all MAC/DMA interrupt sources.
+ */
+static void prvEMACHandlerTask( void *pvParameters );
+
+/*-----------------------------------------------------------*/
+
+/* EMAC data/descriptions. */
+static xemacpsif_s xEMACpsif;
+struct xtopology_t xXTopology =
+{
+ .emac_baseaddr = XPAR_PS7_ETHERNET_0_BASEADDR,
+ .emac_type = xemac_type_emacps,
+ .intc_baseaddr = 0x0,
+ .intc_emac_intr = 0x0,
+ .scugic_baseaddr = XPAR_PS7_SCUGIC_0_BASEADDR,
+ .scugic_emac_intr = 0x36,
+};
+
+XEmacPs_Config mac_config =
+{
+ .DeviceId = XPAR_PS7_ETHERNET_0_DEVICE_ID, /**< Unique ID of device */
+ .BaseAddress = XPAR_PS7_ETHERNET_0_BASEADDR /**< Physical base address of IPIF registers */
+};
+
+extern int phy_detected;
+
+/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
+static uint32_t ulPHYLinkStatus = 0;
+
+#if( ipconfigUSE_LLMNR == 1 )
+ static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
+#endif
+
+/* ucMACAddress as it appears in main.c */
+extern const uint8_t ucMACAddress[ 6 ];
+
+/* Holds the handle of the task used as a deferred interrupt processor. The
+handle is used so direct notifications can be sent to the task for all EMAC/DMA
+related interrupts. */
+TaskHandle_t xEMACTaskHandle = NULL;
+
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceInitialise( void )
+{
+uint32_t ulLinkSpeed, ulDMAReg;
+BaseType_t xStatus, xLinkStatus;
+XEmacPs *pxEMAC_PS;
+const TickType_t xWaitLinkDelay = pdMS_TO_TICKS( 7000UL ), xWaitRelinkDelay = pdMS_TO_TICKS( 1000UL );
+
+ /* Guard against the init function being called more than once. */
+ if( xEMACTaskHandle == NULL )
+ {
+ pxEMAC_PS = &( xEMACpsif.emacps );
+ memset( &xEMACpsif, '\0', sizeof( xEMACpsif ) );
+
+ xStatus = XEmacPs_CfgInitialize( pxEMAC_PS, &mac_config, mac_config.BaseAddress);
+ if( xStatus != XST_SUCCESS )
+ {
+ FreeRTOS_printf( ( "xEMACInit: EmacPs Configuration Failed....\n" ) );
+ }
+
+ /* Initialize the mac and set the MAC address. */
+ XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) ucMACAddress, 1 );
+
+ #if( ipconfigUSE_LLMNR == 1 )
+ {
+ /* Also add LLMNR multicast MAC address. */
+ XEmacPs_SetMacAddress( pxEMAC_PS, ( void * )xLLMNR_MACAddress, 2 );
+ }
+ #endif /* ipconfigUSE_LLMNR == 1 */
+
+ XEmacPs_SetMdioDivisor( pxEMAC_PS, MDC_DIV_224 );
+ ulLinkSpeed = Phy_Setup( pxEMAC_PS );
+ XEmacPs_SetOperatingSpeed( pxEMAC_PS, ulLinkSpeed);
+
+ /* Setting the operating speed of the MAC needs a delay. */
+ vTaskDelay( pdMS_TO_TICKS( 25UL ) );
+
+ ulDMAReg = XEmacPs_ReadReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET);
+
+ /* DISC_WHEN_NO_AHB: when set, the GEM DMA will automatically discard receive
+ packets from the receiver packet buffer memory when no AHB resource is available. */
+ XEmacPs_WriteReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET,
+ ulDMAReg | XEMACPS_DMACR_DISC_WHEN_NO_AHB_MASK);
+
+ setup_isr( &xEMACpsif );
+ init_dma( &xEMACpsif );
+ start_emacps( &xEMACpsif );
+
+ prvGMACWaitLS( xWaitLinkDelay );
+
+ /* The deferred interrupt handler task is created at the highest
+ possible priority to ensure the interrupt handler can return directly
+ to it. The task's handle is stored in xEMACTaskHandle so interrupts can
+ notify the task when there is something to process. */
+ xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
+ }
+ else
+ {
+ /* Initialisation was already performed, just wait for the link. */
+ prvGMACWaitLS( xWaitRelinkDelay );
+ }
+
+ /* Only return pdTRUE when the Link Status of the PHY is high, otherwise the
+ DHCP process and all other communication will fail. */
+ xLinkStatus = xGetPhyLinkStatus();
+
+ return ( xLinkStatus != pdFALSE );
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxBuffer, BaseType_t bReleaseAfterSend )
+{
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ iptraceNETWORK_INTERFACE_TRANSMIT();
+ emacps_send_message( &xEMACpsif, pxBuffer, bReleaseAfterSend );
+ }
+ else if( bReleaseAfterSend != pdFALSE )
+ {
+ /* No link. */
+ vReleaseNetworkBufferAndDescriptor( pxBuffer );
+ }
+
+ return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+static inline unsigned long ulReadMDIO( unsigned ulRegister )
+{
+uint16_t usValue;
+
+ XEmacPs_PhyRead( &( xEMACpsif.emacps ), phy_detected, ulRegister, &usValue );
+ return usValue;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvGMACWaitLS( TickType_t xMaxTime )
+{
+TickType_t xStartTime, xEndTime;
+const TickType_t xShortDelay = pdMS_TO_TICKS( 20UL );
+BaseType_t xReturn;
+
+ xStartTime = xTaskGetTickCount();
+
+ for( ;; )
+ {
+ xEndTime = xTaskGetTickCount();
+
+ if( xEndTime - xStartTime > xMaxTime )
+ {
+ xReturn = pdFALSE;
+ break;
+ }
+ ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
+
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ xReturn = pdTRUE;
+ break;
+ }
+
+ vTaskDelay( xShortDelay );
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
+{
+static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );
+uint8_t *ucRAMBuffer = ucNetworkPackets;
+uint32_t ul;
+
+ for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
+ {
+ pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
+ *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
+ ucRAMBuffer += niBUFFER_1_PACKET_SIZE;
+ }
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xGetPhyLinkStatus( void )
+{
+BaseType_t xReturn;
+
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
+ {
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static void prvEMACHandlerTask( void *pvParameters )
+{
+TimeOut_t xPhyTime;
+TickType_t xPhyRemTime;
+UBaseType_t uxLastMinBufferCount = 0;
+UBaseType_t uxCurrentCount;
+BaseType_t xResult = 0;
+uint32_t xStatus;
+const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
+
+ /* Remove compiler warnings about unused parameters. */
+ ( void ) pvParameters;
+
+ /* A possibility to set some additional task properties like calling
+ portTASK_USES_FLOATING_POINT() */
+ iptraceEMAC_TASK_STARTING();
+
+ vTaskSetTimeOutState( &xPhyTime );
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+
+ for( ;; )
+ {
+ uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
+ if( uxLastMinBufferCount != uxCurrentCount )
+ {
+ /* The logging produced below may be helpful
+ while tuning +TCP: see how many buffers are in use. */
+ uxLastMinBufferCount = uxCurrentCount;
+ FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
+ uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
+ }
+
+ #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+ {
+ static UBaseType_t uxLastMinQueueSpace = 0;
+
+ uxCurrentCount = uxGetMinimumIPQueueSpace();
+ if( uxLastMinQueueSpace != uxCurrentCount )
+ {
+ /* The logging produced below may be helpful
+ while tuning +TCP: see how many buffers are in use. */
+ uxLastMinQueueSpace = uxCurrentCount;
+ FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
+ }
+ }
+ #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
+
+ if( ( xEMACpsif.isr_events & EMAC_IF_ALL_EVENT ) == 0 )
+ {
+ /* No events to process now, wait for the next. */
+ ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
+ }
+
+ if( ( xEMACpsif.isr_events & EMAC_IF_RX_EVENT ) != 0 )
+ {
+ xEMACpsif.isr_events &= ~EMAC_IF_RX_EVENT;
+ xResult = emacps_check_rx( &xEMACpsif );
+ }
+
+ if( ( xEMACpsif.isr_events & EMAC_IF_TX_EVENT ) != 0 )
+ {
+ xEMACpsif.isr_events &= ~EMAC_IF_TX_EVENT;
+ emacps_check_tx( &xEMACpsif );
+ }
+
+ if( ( xEMACpsif.isr_events & EMAC_IF_ERR_EVENT ) != 0 )
+ {
+ xEMACpsif.isr_events &= ~EMAC_IF_ERR_EVENT;
+ emacps_check_errors( &xEMACpsif );
+ }
+
+ if( xResult > 0 )
+ {
+ /* A packet was received. No need to check for the PHY status now,
+ but set a timer to check it later on. */
+ vTaskSetTimeOutState( &xPhyTime );
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+ xResult = 0;
+ }
+ else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
+ {
+ xStatus = ulReadMDIO( PHY_REG_01_BMSR );
+
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
+ {
+ ulPHYLinkStatus = xStatus;
+ FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
+ }
+
+ vTaskSetTimeOutState( &xPhyTime );
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+ }
+ else
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt
new file mode 100644
index 000000000..74b241dcf
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt
@@ -0,0 +1,25 @@
+
+
+NetworkInterface for Xilinx' Zynq
+
+Please include the following source files:
+
+ $(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/NetworkInterface.c
+ $(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
+ $(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c
+ $(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/x_emacpsif_hw.c
+
+And include the following source files from the Xilinx library:
+
+ $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps.c
+ $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_control.c
+ $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_g.c
+ $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_intr.c
+
+ E.g. ps7_cortexa9_0/libsrc/emacps_v2_0/src/xemacps_intr.c
+
+The following source files are NOT used for the FreeRTOS+TCP interface:
+
+ $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_bdring.c
+ $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_hw.c
+ $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_sinit.c
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h
new file mode 100644
index 000000000..823dee0d3
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2010-2013 Xilinx, Inc. All rights reserved.
+ *
+ * Xilinx, Inc.
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
+ * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
+ * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
+ * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
+ * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
+ * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
+ * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
+ * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
+ * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
+ * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef __NETIF_XEMACPSIF_H__
+#define __NETIF_XEMACPSIF_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include "xstatus.h"
+#include "sleep.h"
+#include "xparameters.h"
+#include "xparameters_ps.h" /* defines XPAR values */
+#include "xil_types.h"
+#include "xil_assert.h"
+#include "xil_io.h"
+#include "xil_exception.h"
+#include "xpseudo_asm.h"
+#include "xil_cache.h"
+#include "xil_printf.h"
+#include "xuartps.h"
+#include "xscugic.h"
+#include "xemacps.h" /* defines XEmacPs API */
+
+//#include "netif/xpqueue.h"
+//#include "xlwipconfig.h"
+
+void xemacpsif_setmac(uint32_t index, uint8_t *addr);
+uint8_t* xemacpsif_getmac(uint32_t index);
+//int xemacpsif_init(struct netif *netif);
+//int xemacpsif_input(struct netif *netif);
+#ifdef NOTNOW_BHILL
+unsigned get_IEEE_phy_speed(XLlTemac *xlltemacp);
+#endif
+
+/* xaxiemacif_hw.c */
+void xemacps_error_handler(XEmacPs * Temac);
+
+struct xBD_TYPE {
+ uint32_t address;
+ uint32_t flags;
+};
+
+/*
+ * Missing declaration in 'src/xemacps_hw.h' :
+ * When set, the GEM DMA will automatically
+ * discard receive packets from the receiver packet
+ * buffer memory when no AHB resource is
+ * available.
+ * When low, then received packets will remain to be
+ * stored in the SRAM based packet buffer until
+ * AHB buffer resource next becomes available.
+ */
+#define XEMACPS_DMACR_DISC_WHEN_NO_AHB_MASK 0x01000000
+
+#define EMAC_IF_RX_EVENT 1
+#define EMAC_IF_TX_EVENT 2
+#define EMAC_IF_ERR_EVENT 4
+#define EMAC_IF_ALL_EVENT 7
+
+/* structure within each netif, encapsulating all information required for
+ * using a particular temac instance
+ */
+typedef struct {
+ XEmacPs emacps;
+
+ /* pointers to memory holding buffer descriptors (used only with SDMA) */
+ struct xBD_TYPE *rxSegments;
+ struct xBD_TYPE *txSegments;
+
+ unsigned char *tx_space;
+ unsigned uTxUnitSize;
+
+ char *remain_mem;
+ unsigned remain_siz;
+
+ volatile int rxHead, rxTail;
+ volatile int txHead, txTail;
+
+ volatile int txBusy;
+
+ volatile uint32_t isr_events;
+
+ unsigned int last_rx_frms_cntr;
+
+} xemacpsif_s;
+
+//extern xemacpsif_s xemacpsif;
+
+int is_tx_space_available(xemacpsif_s *emac);
+
+/* xaxiemacif_dma.c */
+
+struct xNETWORK_BUFFER;
+
+int emacps_check_rx( xemacpsif_s *xemacpsif );
+void emacps_check_tx( xemacpsif_s *xemacpsif );
+int emacps_check_errors( xemacpsif_s *xemacps );
+void emacps_set_rx_buffers( xemacpsif_s *xemacpsif, u32 ulCount );
+
+extern XStatus emacps_send_message(xemacpsif_s *xemacpsif, struct xNETWORK_BUFFER *pxBuffer, int iReleaseAfterSend );
+extern unsigned Phy_Setup( XEmacPs *xemacpsp );
+extern void setup_isr( xemacpsif_s *xemacpsif );
+extern XStatus init_dma( xemacpsif_s *xemacpsif );
+extern void start_emacps( xemacpsif_s *xemacpsif );
+
+void EmacEnableIntr(void);
+void EmacDisableIntr(void);
+
+XStatus init_axi_dma(xemacpsif_s *xemacpsif);
+void process_sent_bds( xemacpsif_s *xemacpsif );
+
+void emacps_send_handler(void *arg);
+void emacps_recv_handler(void *arg);
+void emacps_error_handler(void *arg,u8 Direction, u32 ErrorWord);
+void HandleTxErrors(xemacpsif_s *xemacpsif);
+XEmacPs_Config *xemacps_lookup_config(unsigned mac_base);
+
+void clean_dma_txdescs(xemacpsif_s *xemacpsif);
+void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NETIF_XAXIEMACIF_H__ */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
new file mode 100644
index 000000000..7a8f204b9
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
@@ -0,0 +1,657 @@
+/*
+ * FreeRTOS+TCP Labs Build 200417 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#include "Zynq/x_emacpsif.h"
+#include "Zynq/x_topology.h"
+#include "xstatus.h"
+
+#include "xparameters.h"
+#include "xparameters_ps.h"
+#include "xil_exception.h"
+#include "xil_mmu.h"
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "timers.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "NetworkBufferManagement.h"
+
+#include "uncached_memory.h"
+
+/* Two defines used to set or clear the EMAC interrupt */
+#define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR
+#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR
+
+
+
+#if( ipconfigPACKET_FILLER_SIZE != 2 )
+ #error Please define ipconfigPACKET_FILLER_SIZE as the value '2'
+#endif
+#define TX_OFFSET ipconfigPACKET_FILLER_SIZE
+
+/* Defined in NetworkInterface.c */
+extern TaskHandle_t xEMACTaskHandle;
+
+/*
+ pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.
+ The actual TX buffers are located in uncached RAM.
+*/
+static unsigned char *pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };
+
+/*
+ pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.
+ Once a message has been received by the EMAC, the descriptor can be passed
+ immediately to the IP-task.
+*/
+static NetworkBufferDescriptor_t *pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };
+
+/*
+ The FreeRTOS+TCP port is using a fixed 'topology', which is declared in
+ ./portable/NetworkInterface/Zynq/NetworkInterface.c
+*/
+extern struct xtopology_t xXTopology;
+
+static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
+
+/*
+ The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".
+ In stead 'struct xemacpsif_s' has a "head" and a "tail" index.
+ "head" is the next index to be written, used.
+ "tail" is the next index to be read, freed.
+*/
+
+int is_tx_space_available( xemacpsif_s *xemacpsif )
+{
+size_t uxCount;
+
+ if( xTXDescriptorSemaphore != NULL )
+ {
+ uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
+ }
+ else
+ {
+ uxCount = ( UBaseType_t ) 0u;
+ }
+
+ return uxCount;
+}
+
+void emacps_check_tx( xemacpsif_s *xemacpsif )
+{
+int tail = xemacpsif->txTail;
+int head = xemacpsif->txHead;
+size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
+
+ /* uxCount is the number of TX descriptors that are in use by the DMA. */
+ /* When done, "TXBUF_USED" will be set. */
+
+ while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )
+ {
+ if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )
+ {
+ break;
+ }
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+#warning ipconfigZERO_COPY_TX_DRIVER is defined
+ {
+ void *pvBuffer = pxDMA_tx_buffers[ tail ];
+ NetworkBufferDescriptor_t *pxBuffer;
+
+ if( pvBuffer != NULL )
+ {
+ pxDMA_tx_buffers[ tail ] = NULL;
+ pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );
+ if( pxBuffer != NULL )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxBuffer );
+ }
+ else
+ {
+ FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );
+ }
+ }
+ }
+#endif
+ /* Clear all but the "used" and "wrap" bits. */
+ if( tail < ipconfigNIC_N_TX_DESC - 1 )
+ {
+ xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;
+ }
+ else
+ {
+ xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
+ }
+ uxCount--;
+ /* Tell the counting semaphore that one more TX descriptor is available. */
+ xSemaphoreGive( xTXDescriptorSemaphore );
+ if( ++tail == ipconfigNIC_N_TX_DESC )
+ {
+ tail = 0;
+ }
+ xemacpsif->txTail = tail;
+ }
+
+ return;
+}
+
+void emacps_send_handler(void *arg)
+{
+xemacpsif_s *xemacpsif;
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+
+ xemacpsif = (xemacpsif_s *)(arg);
+
+ /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in
+ "isr_events". The task in NetworkInterface will wake-up and do the necessary work.
+ */
+ xemacpsif->isr_events |= EMAC_IF_TX_EVENT;
+ xemacpsif->txBusy = pdFALSE;
+
+ if( xEMACTaskHandle != NULL )
+ {
+ vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
+ }
+
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+}
+
+static BaseType_t xValidLength( BaseType_t xLength )
+{
+BaseType_t xReturn;
+
+ if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) )
+ {
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+
+ return xReturn;
+}
+
+XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend )
+{
+int head = xemacpsif->txHead;
+int tail = xemacpsif->txTail;
+int iHasSent = 0;
+uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;
+TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );
+
+ #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ {
+ /* This driver wants to own all network buffers which are to be transmitted. */
+ configASSERT( iReleaseAfterSend != pdFALSE );
+ }
+ #endif
+
+ /* Open a do {} while ( 0 ) loop to be able to call break. */
+ do
+ {
+ uint32_t ulFlags = 0;
+
+ if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )
+ {
+ break;
+ }
+
+ if( xTXDescriptorSemaphore == NULL )
+ {
+ break;
+ }
+
+ if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
+ {
+ FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );
+ break;
+ }
+
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ /* Pass the pointer (and its ownership) directly to DMA. */
+ pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;
+ if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
+ {
+ Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
+ }
+ /* Buffer has been transferred, do not release it. */
+ iReleaseAfterSend = pdFALSE;
+#else
+ if( pxDMA_tx_buffers[ head ] == NULL )
+ {
+ FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) );
+ break;
+ }
+ /* Copy the message to unbuffered space in RAM. */
+ memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
+#endif
+ /* Packets will be sent one-by-one, so for each packet
+ the TXBUF_LAST bit will be set. */
+ ulFlags |= XEMACPS_TXBUF_LAST_MASK;
+ ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );
+ if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )
+ {
+ ulFlags |= XEMACPS_TXBUF_WRAP_MASK;
+ }
+
+ /* Copy the address of the buffer and set the flags. */
+ xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];
+ xemacpsif->txSegments[ head ].flags = ulFlags;
+
+ iHasSent = pdTRUE;
+ if( ++head == ipconfigNIC_N_TX_DESC )
+ {
+ head = 0;
+ }
+ /* Update the TX-head index. These variable are declared volatile so they will be
+ accessed as little as possible. */
+ xemacpsif->txHead = head;
+ } while( pdFALSE );
+
+ if( iReleaseAfterSend != pdFALSE )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxBuffer );
+ pxBuffer = NULL;
+ }
+
+ /* Data Synchronization Barrier */
+ dsb();
+
+ if( iHasSent != pdFALSE )
+ {
+ /* Make STARTTX high */
+ uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);
+ /* Start transmit */
+ xemacpsif->txBusy = pdTRUE;
+ XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );
+ }
+ dsb();
+
+ return 0;
+}
+
+void emacps_recv_handler(void *arg)
+{
+ xemacpsif_s *xemacpsif;
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+
+ xemacpsif = (xemacpsif_s *)(arg);
+ xemacpsif->isr_events |= EMAC_IF_RX_EVENT;
+
+ if( xEMACTaskHandle != NULL )
+ {
+ vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
+ }
+
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+}
+
+static NetworkBufferDescriptor_t *ethMsg = NULL;
+static NetworkBufferDescriptor_t *ethLast = NULL;
+
+static void passEthMessages( void )
+{
+IPStackEvent_t xRxEvent;
+
+ xRxEvent.eEventType = eNetworkRxEvent;
+ xRxEvent.pvData = ( void * ) ethMsg;
+
+ if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )
+ {
+ /* The buffer could not be sent to the stack so must be released again.
+ This is a deferred handler taskr, not a real interrupt, so it is ok to
+ use the task level function here. */
+ do
+ {
+ NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer;
+ vReleaseNetworkBufferAndDescriptor( ethMsg );
+ ethMsg = xNext;
+ } while( ethMsg != NULL );
+
+ iptraceETHERNET_RX_EVENT_LOST();
+ FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) );
+ }
+
+ ethMsg = ethLast = NULL;
+}
+
+int emacps_check_rx( xemacpsif_s *xemacpsif )
+{
+NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;
+int rx_bytes;
+volatile int msgCount = 0;
+int head = xemacpsif->rxHead;
+
+ /* There seems to be an issue (SI# 692601), see comments below. */
+ resetrx_on_no_rxdata(xemacpsif);
+
+ /* This FreeRTOS+TCP driver shall be compiled with the option
+ "ipconfigUSE_LINKED_RX_MESSAGES" enabled. It allows the driver to send a
+ chain of RX messages within one message to the IP-task. */
+ for( ;; )
+ {
+ if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
+ ( pxDMA_rx_buffers[ head ] == NULL ) )
+ {
+ break;
+ }
+
+ pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );
+ if( pxNewBuffer == NULL )
+ {
+ /* A packet has been received, but there is no replacement for this Network Buffer.
+ The packet will be dropped, and it Network Buffer will stay in place. */
+ FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );
+ pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
+ }
+ else
+ {
+ pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
+
+ /* Just avoiding to use or refer to the same buffer again */
+ pxDMA_rx_buffers[ head ] = pxNewBuffer;
+
+ /*
+ * Adjust the buffer size to the actual number of bytes received.
+ */
+ rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;
+
+ pxBuffer->xDataLength = rx_bytes;
+
+ if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
+ {
+ Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes );
+ }
+
+ /* store it in the receive queue, where it'll be processed by a
+ different handler. */
+ iptraceNETWORK_INTERFACE_RECEIVE();
+ pxBuffer->pxNextBuffer = NULL;
+
+ if( ethMsg == NULL )
+ {
+ // Becomes the first message
+ ethMsg = pxBuffer;
+ }
+ else if( ethLast != NULL )
+ {
+ // Add to the tail
+ ethLast->pxNextBuffer = pxBuffer;
+ }
+
+ ethLast = pxBuffer;
+ msgCount++;
+ }
+ {
+ if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )
+ {
+ Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );
+ }
+ {
+ uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
+ if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )
+ {
+ addr |= XEMACPS_RXBUF_WRAP_MASK;
+ }
+ /* Clearing 'XEMACPS_RXBUF_NEW_MASK' 0x00000001 *< Used bit.. */
+ xemacpsif->rxSegments[ head ].address = addr;
+ xemacpsif->rxSegments[ head ].flags = 0;
+ }
+ }
+
+ if( ++head == ipconfigNIC_N_RX_DESC )
+ {
+ head = 0;
+ }
+ xemacpsif->rxHead = head;
+ }
+
+ if( ethMsg != NULL )
+ {
+ passEthMessages( );
+ }
+
+ return msgCount;
+}
+
+void clean_dma_txdescs(xemacpsif_s *xemacpsif)
+{
+int index;
+unsigned char *ucTxBuffer;
+
+ /* Clear all TX descriptors and assign uncached memory to each descriptor.
+ "tx_space" points to the first available TX buffer. */
+ ucTxBuffer = xemacpsif->tx_space;
+
+ for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )
+ {
+ xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;
+ xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+ pxDMA_tx_buffers[ index ] = ( void* )NULL;
+#else
+ pxDMA_tx_buffers[ index ] = ( void* )( ucTxBuffer + TX_OFFSET );
+#endif
+ ucTxBuffer += xemacpsif->uTxUnitSize;
+ }
+ xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =
+ XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
+}
+
+XStatus init_dma(xemacpsif_s *xemacpsif)
+{
+ NetworkBufferDescriptor_t *pxBuffer;
+
+ int iIndex;
+ UBaseType_t xRxSize;
+ UBaseType_t xTxSize;
+ struct xtopology_t *xtopologyp = &xXTopology;
+
+ xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );
+
+ xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );
+
+ /* Also round-up to 4KB */
+ xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;
+ /*
+ * We allocate 65536 bytes for RX BDs which can accommodate a
+ * maximum of 8192 BDs which is much more than any application
+ * will ever need.
+ */
+ xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize ) );
+ xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );
+ xemacpsif->tx_space = ( unsigned char * )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );
+
+ /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */
+ xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;
+ xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;
+
+ if( xTXDescriptorSemaphore == NULL )
+ {
+ xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );
+ configASSERT( xTXDescriptorSemaphore );
+ }
+ /*
+ * Allocate RX descriptors, 1 RxBD at a time.
+ */
+ for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )
+ {
+ pxBuffer = pxDMA_rx_buffers[ iIndex ];
+ if( pxBuffer == NULL )
+ {
+ pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );
+ if( pxBuffer == NULL )
+ {
+ FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );
+ return -1;
+ }
+ }
+
+ xemacpsif->rxSegments[ iIndex ].flags = 0;
+ xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
+
+ pxDMA_rx_buffers[ iIndex ] = pxBuffer;
+ /* Make sure this memory is not in cache for now. */
+ if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
+ {
+ Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,
+ (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );
+ }
+ }
+
+ xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;
+
+ memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );
+
+ clean_dma_txdescs( xemacpsif );
+
+ {
+ uint32_t value;
+ value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );
+
+ // 1xxxx: Attempt to use INCR16 AHB bursts
+ value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;
+#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
+ value |= XEMACPS_DMACR_TCPCKSUM_MASK;
+#else
+#warning Are you sure the EMAC should not calculate outgoing checksums?
+ value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;
+#endif
+ XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );
+ }
+ {
+ uint32_t value;
+ value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );
+
+ /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).
+ Now tell the EMAC that received messages should be stored at "address + 2". */
+ value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;
+
+#if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
+ value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
+#else
+#warning Are you sure the EMAC should not calculate incoming checksums?
+ value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;
+#endif
+ XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );
+ }
+
+ /*
+ * Connect the device driver handler that will be called when an
+ * interrupt for the device occurs, the handler defined above performs
+ * the specific interrupt processing for the device.
+ */
+ XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,
+ (Xil_ExceptionHandler)XEmacPs_IntrHandler,
+ (void *)&xemacpsif->emacps);
+ /*
+ * Enable the interrupt for emacps.
+ */
+ EmacEnableIntr( );
+
+ return 0;
+}
+
+/*
+ * resetrx_on_no_rxdata():
+ *
+ * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
+ * called by the user.
+ * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
+ * Under heavy Rx traffic because of the HW bug there are times when the Rx path
+ * becomes unresponsive. The workaround for it is to check for the Rx path for
+ * traffic (by reading the stats registers regularly). If the stats register
+ * does not increment for sometime (proving no Rx traffic), the function resets
+ * the Rx data path.
+ *
+ */
+
+void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
+{
+ unsigned long regctrl;
+ unsigned long tempcntr;
+
+ tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );
+ if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )
+ {
+ regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
+ XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, regctrl);
+ regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);
+ regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
+ XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);
+ }
+ xemacpsif->last_rx_frms_cntr = tempcntr;
+}
+
+void EmacDisableIntr(void)
+{
+ XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
+}
+
+void EmacEnableIntr(void)
+{
+ XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
+}
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c
new file mode 100644
index 000000000..e9443cda8
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2010-2013 Xilinx, Inc. All rights reserved.
+ *
+ * Xilinx, Inc.
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
+ * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
+ * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
+ * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
+ * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
+ * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
+ * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
+ * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
+ * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
+ * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "Zynq/x_emacpsif.h"
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+///* FreeRTOS+TCP includes. */
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "NetworkBufferManagement.h"
+
+extern TaskHandle_t xEMACTaskHandle;
+
+/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c
+ *** to run it on a PEEP board
+ ***/
+
+unsigned int link_speed = 100;
+
+void setup_isr( xemacpsif_s *xemacpsif )
+{
+ /*
+ * Setup callbacks
+ */
+ XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMASEND,
+ (void *) emacps_send_handler,
+ (void *) xemacpsif);
+
+ XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMARECV,
+ (void *) emacps_recv_handler,
+ (void *) xemacpsif);
+
+ XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_ERROR,
+ (void *) emacps_error_handler,
+ (void *) xemacpsif);
+}
+
+void start_emacps (xemacpsif_s *xemacps)
+{
+ /* start the temac */
+ XEmacPs_Start(&xemacps->emacps);
+}
+
+extern struct xtopology_t xXTopology;
+
+volatile int error_msg_count = 0;
+volatile const char *last_err_msg = "";
+
+struct xERROR_MSG {
+ void *arg;
+ u8 Direction;
+ u32 ErrorWord;
+};
+
+static struct xERROR_MSG xErrorList[ 8 ];
+static BaseType_t xErrorHead, xErrorTail;
+
+void emacps_error_handler(void *arg, u8 Direction, u32 ErrorWord)
+{
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+ xemacpsif_s *xemacpsif;
+ BaseType_t xNextHead = xErrorHead;
+
+ xemacpsif = (xemacpsif_s *)(arg);
+
+ if( ( Direction != XEMACPS_SEND ) || (ErrorWord != XEMACPS_TXSR_USEDREAD_MASK ) )
+ {
+ if( ++xNextHead == ( sizeof( xErrorList ) / sizeof( xErrorList[ 0 ] ) ) )
+ xNextHead = 0;
+ if( xNextHead != xErrorTail )
+ {
+
+ xErrorList[ xErrorHead ].arg = arg;
+ xErrorList[ xErrorHead ].Direction = Direction;
+ xErrorList[ xErrorHead ].ErrorWord = ErrorWord;
+
+ xErrorHead = xNextHead;
+
+ xemacpsif = (xemacpsif_s *)(arg);
+ xemacpsif->isr_events |= EMAC_IF_ERR_EVENT;
+ }
+
+ if( xEMACTaskHandle != NULL )
+ {
+ vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
+ }
+
+ }
+
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+}
+
+static void emacps_handle_error(void *arg, u8 Direction, u32 ErrorWord);
+
+int emacps_check_errors( xemacpsif_s *xemacps )
+{
+int xResult;
+
+ ( void ) xemacps;
+
+ if( xErrorHead == xErrorTail )
+ {
+ xResult = 0;
+ }
+ else
+ {
+ xResult = 1;
+ emacps_handle_error(
+ xErrorList[ xErrorTail ].arg,
+ xErrorList[ xErrorTail ].Direction,
+ xErrorList[ xErrorTail ].ErrorWord );
+ }
+
+ return xResult;
+}
+
+BaseType_t xNetworkInterfaceInitialise( void );
+
+static void emacps_handle_error(void *arg, u8 Direction, u32 ErrorWord)
+{
+ xemacpsif_s *xemacpsif;
+ struct xtopology_t *xtopologyp;
+ XEmacPs *xemacps;
+
+ xemacpsif = (xemacpsif_s *)(arg);
+
+ xtopologyp = &xXTopology;
+
+ xemacps = &xemacpsif->emacps;
+
+ /* Do not appear to be used. */
+ ( void ) xemacps;
+ ( void ) xtopologyp;
+
+ last_err_msg = NULL;
+
+ if( ErrorWord != 0 )
+ {
+ switch (Direction) {
+ case XEMACPS_RECV:
+ if( ( ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK ) != 0 )
+ {
+ last_err_msg = "Receive DMA error";
+ xNetworkInterfaceInitialise( );
+ }
+ if( ( ErrorWord & XEMACPS_RXSR_RXOVR_MASK ) != 0 )
+ {
+ last_err_msg = "Receive over run";
+ emacps_recv_handler(arg);
+ }
+ if( ( ErrorWord & XEMACPS_RXSR_BUFFNA_MASK ) != 0 )
+ {
+ last_err_msg = "Receive buffer not available";
+ emacps_recv_handler(arg);
+ }
+ break;
+ case XEMACPS_SEND:
+ if( ( ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK ) != 0 )
+ {
+ last_err_msg = "Transmit DMA error";
+ xNetworkInterfaceInitialise( );
+ }
+ if( ( ErrorWord & XEMACPS_TXSR_URUN_MASK ) != 0 )
+ {
+ last_err_msg = "Transmit under run";
+ HandleTxErrors( xemacpsif );
+ }
+ if( ( ErrorWord & XEMACPS_TXSR_BUFEXH_MASK ) != 0 )
+ {
+ last_err_msg = "Transmit buffer exhausted";
+ HandleTxErrors( xemacpsif );
+ }
+ if( ( ErrorWord & XEMACPS_TXSR_RXOVR_MASK ) != 0 )
+ {
+ last_err_msg = "Transmit retry excessed limits";
+ HandleTxErrors( xemacpsif );
+ }
+ if( ( ErrorWord & XEMACPS_TXSR_FRAMERX_MASK ) != 0 )
+ {
+ last_err_msg = "Transmit collision";
+ emacps_check_tx( xemacpsif );
+ }
+ break;
+ }
+ }
+ // Break on this statement and inspect error_msg if you like
+ if( last_err_msg != NULL )
+ {
+ error_msg_count++;
+ FreeRTOS_printf( ( "emacps_handle_error: %s\n", last_err_msg ) );
+ }
+}
+
+extern XEmacPs_Config mac_config;
+
+void HandleTxErrors(xemacpsif_s *xemacpsif)
+{
+ u32 netctrlreg;
+
+ //taskENTER_CRITICAL()
+ {
+ netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ netctrlreg = netctrlreg & (~XEMACPS_NWCTRL_TXEN_MASK);
+ XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, netctrlreg);
+
+ clean_dma_txdescs( xemacpsif );
+ netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ netctrlreg = netctrlreg | (XEMACPS_NWCTRL_TXEN_MASK);
+ XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, netctrlreg);
+ }
+ //taskEXIT_CRITICAL( );
+}
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.h
new file mode 100644
index 000000000..f3c424a4b
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010-2013 Xilinx, Inc. All rights reserved.
+ *
+ * Xilinx, Inc.
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
+ * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
+ * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
+ * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
+ * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
+ * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
+ * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
+ * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
+ * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
+ * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef __XEMACPSIF_HW_H_
+#define __XEMACPSIF_HW_H_
+
+#include "Zynq/x_emacpsif.h"
+//#include "lwip/netif.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+XEmacPs_Config * lookup_config(unsigned mac_base);
+
+//void init_emacps(xemacpsif_s *xemacpsif, struct netif *netif);
+
+int emacps_check_errors( xemacpsif_s *xemacps );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c
new file mode 100644
index 000000000..12b8c60c8
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2007-2008, Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Advanced Micro Devices, Inc. nor the names
+ * of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Some portions copyright (c) 2010-2013 Xilinx, Inc. All rights reserved.
+ *
+ * Xilinx, Inc.
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
+ * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
+ * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
+ * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
+ * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
+ * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
+ * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
+ * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
+ * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
+ * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "Zynq/x_emacpsif.h"
+//#include "lwipopts.h"
+#include "xparameters_ps.h"
+#include "xparameters.h"
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+///* FreeRTOS+TCP includes. */
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "NetworkBufferManagement.h"
+
+int phy_detected = 0;
+
+/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c
+ *** to run it on a PEEP board
+ ***/
+
+/* Advertisement control register. */
+#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
+#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
+#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
+
+#define ADVERTISE_100_AND_10 (ADVERTISE_10FULL | ADVERTISE_100FULL | \
+ ADVERTISE_10HALF | ADVERTISE_100HALF)
+#define ADVERTISE_100 (ADVERTISE_100FULL | ADVERTISE_100HALF)
+#define ADVERTISE_10 (ADVERTISE_10FULL | ADVERTISE_10HALF)
+
+#define ADVERTISE_1000 0x0300
+
+
+//#define PHY_REG_00_BMCR 0x00 // Basic mode control register
+//#define PHY_REG_01_BMSR 0x01 // Basic mode status register
+//#define PHY_REG_02_PHYSID1 0x02 // PHYS ID 1
+//#define PHY_REG_03_PHYSID2 0x03 // PHYS ID 2
+//#define PHY_REG_04_ADVERTISE 0x04 // Advertisement control reg
+
+#define IEEE_CONTROL_REG_OFFSET 0
+#define IEEE_STATUS_REG_OFFSET 1
+#define IEEE_AUTONEGO_ADVERTISE_REG 4
+#define IEEE_PARTNER_ABILITIES_1_REG_OFFSET 5
+#define IEEE_1000_ADVERTISE_REG_OFFSET 9
+#define IEEE_PARTNER_ABILITIES_3_REG_OFFSET 10
+#define IEEE_COPPER_SPECIFIC_CONTROL_REG 16
+#define IEEE_SPECIFIC_STATUS_REG 17
+#define IEEE_COPPER_SPECIFIC_STATUS_REG_2 19
+#define IEEE_CONTROL_REG_MAC 21
+#define IEEE_PAGE_ADDRESS_REGISTER 22
+
+
+#define IEEE_CTRL_1GBPS_LINKSPEED_MASK 0x2040
+#define IEEE_CTRL_LINKSPEED_MASK 0x0040
+#define IEEE_CTRL_LINKSPEED_1000M 0x0040
+#define IEEE_CTRL_LINKSPEED_100M 0x2000
+#define IEEE_CTRL_LINKSPEED_10M 0x0000
+#define IEEE_CTRL_RESET_MASK 0x8000
+#define IEEE_CTRL_AUTONEGOTIATE_ENABLE 0x1000
+#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
+#define IEEE_CTRL_RESET 0x9140
+#define IEEE_CTRL_ISOLATE_DISABLE 0xFBFF
+#endif
+#define IEEE_STAT_AUTONEGOTIATE_CAPABLE 0x0008
+#define IEEE_STAT_AUTONEGOTIATE_COMPLETE 0x0020
+#define IEEE_STAT_AUTONEGOTIATE_RESTART 0x0200
+#define IEEE_STAT_1GBPS_EXTENSIONS 0x0100
+#define IEEE_AN1_ABILITY_MASK 0x1FE0
+#define IEEE_AN3_ABILITY_MASK_1GBPS 0x0C00
+#define IEEE_AN1_ABILITY_MASK_100MBPS 0x0380
+#define IEEE_AN1_ABILITY_MASK_10MBPS 0x0060
+#define IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK 0x0030
+
+#define IEEE_ASYMMETRIC_PAUSE_MASK 0x0800
+#define IEEE_PAUSE_MASK 0x0400
+#define IEEE_AUTONEG_ERROR_MASK 0x8000
+
+#define PHY_DETECT_REG 1
+#define PHY_DETECT_MASK 0x1808
+
+#define XEMACPS_GMII2RGMII_SPEED1000_FD 0x140
+#define XEMACPS_GMII2RGMII_SPEED100_FD 0x2100
+#define XEMACPS_GMII2RGMII_SPEED10_FD 0x100
+#define XEMACPS_GMII2RGMII_REG_NUM 0x10
+
+/* Frequency setting */
+#define SLCR_LOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x4)
+#define SLCR_UNLOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x8)
+#define SLCR_GEM0_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x140)
+#define SLCR_GEM1_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x144)
+#ifdef PEEP
+#define SLCR_GEM_10M_CLK_CTRL_VALUE 0x00103031
+#define SLCR_GEM_100M_CLK_CTRL_VALUE 0x00103001
+#define SLCR_GEM_1G_CLK_CTRL_VALUE 0x00103011
+#endif
+#define SLCR_LOCK_KEY_VALUE 0x767B
+#define SLCR_UNLOCK_KEY_VALUE 0xDF0D
+#define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214)
+#define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF
+
+#define EMAC0_BASE_ADDRESS 0xE000B000
+#define EMAC1_BASE_ADDRESS 0xE000C000
+
+static int detect_phy(XEmacPs *xemacpsp)
+{
+ u16 phy_reg;
+ u32 phy_addr;
+
+ for (phy_addr = 31; phy_addr > 0; phy_addr--) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_DETECT_REG,
+ &phy_reg);
+
+ if ((phy_reg != 0xFFFF) &&
+ ((phy_reg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
+ /* Found a valid PHY address */
+ FreeRTOS_printf( ("XEmacPs detect_phy: PHY detected at address %d.\r\n",
+ phy_addr));
+ FreeRTOS_printf( ("XEmacPs detect_phy: PHY detected.\n" ) );
+ phy_detected = phy_addr;
+ return phy_addr;
+ }
+ }
+
+ FreeRTOS_printf( ("XEmacPs detect_phy: No PHY detected. Assuming a PHY at address 0\n" ) );
+
+ /* default to zero */
+ return 0;
+}
+
+#ifdef PEEP
+unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp)
+{
+
+ u16 control;
+ u16 status;
+ u16 partner_capabilities;
+ u16 partner_capabilities_1000;
+ u16 phylinkspeed;
+ u32 phy_addr = detect_phy(xemacpsp);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ ADVERTISE_1000);
+ /* Advertise PHY speed of 100 and 10 Mbps */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG,
+ ADVERTISE_100_AND_10);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET,
+ &control);
+ control |= (IEEE_CTRL_AUTONEGOTIATE_ENABLE |
+ IEEE_STAT_AUTONEGOTIATE_RESTART);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ /* Read PHY control and status registers is successful. */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ if ((control & IEEE_CTRL_AUTONEGOTIATE_ENABLE) && (status &
+ IEEE_STAT_AUTONEGOTIATE_CAPABLE)) {
+
+ while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
+ &status);
+ }
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET,
+ &partner_capabilities);
+
+ if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_3_REG_OFFSET,
+ &partner_capabilities_1000);
+ if (partner_capabilities_1000 & IEEE_AN3_ABILITY_MASK_1GBPS)
+ return 1000;
+ }
+
+ if (partner_capabilities & IEEE_AN1_ABILITY_MASK_100MBPS)
+ return 100;
+ if (partner_capabilities & IEEE_AN1_ABILITY_MASK_10MBPS)
+ return 10;
+
+ xil_printf("%s: unknown PHY link speed, setting TEMAC speed to be 10 Mbps\r\n",
+ __FUNCTION__);
+ return 10;
+
+ } else {
+
+ /* Update TEMAC speed accordingly */
+ if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
+ /* Get commanded link speed */
+ phylinkspeed = control & IEEE_CTRL_1GBPS_LINKSPEED_MASK;
+
+ switch (phylinkspeed) {
+ case (IEEE_CTRL_LINKSPEED_1000M):
+ return 1000;
+ case (IEEE_CTRL_LINKSPEED_100M):
+ return 100;
+ case (IEEE_CTRL_LINKSPEED_10M):
+ return 10;
+ default:
+ xil_printf("%s: unknown PHY link speed (%d), setting TEMAC speed to be 10 Mbps\r\n",
+ __FUNCTION__, phylinkspeed);
+ return 10;
+ }
+
+ } else {
+
+ return (control & IEEE_CTRL_LINKSPEED_MASK) ? 100 : 10;
+
+ }
+ }
+}
+
+#else /* Zynq */
+unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp)
+{
+ u16 temp;
+ u16 control;
+ u16 status;
+ u16 partner_capabilities;
+#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
+ u32 phy_addr = XPAR_PCSPMA_SGMII_PHYADDR;
+#else
+ u32 phy_addr = detect_phy(xemacpsp);
+#endif
+ xil_printf("Start PHY autonegotiation \r\n");
+
+#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
+#else
+ XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
+ control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
+ control |= IEEE_ASYMMETRIC_PAUSE_MASK;
+ control |= IEEE_PAUSE_MASK;
+ control |= ADVERTISE_100;
+ control |= ADVERTISE_10;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ &control);
+ control |= ADVERTISE_1000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ control);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
+ &control);
+ control |= (7 << 12); /* max number of gigabit attempts */
+ control |= (1 << 11); /* enable downshift */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
+ control);
+#endif
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
+ control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
+#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
+ control &= IEEE_CTRL_ISOLATE_DISABLE;
+#endif
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+
+#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
+#else
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_RESET_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ while (1) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ if (control & IEEE_CTRL_RESET_MASK)
+ continue;
+ else
+ break;
+ }
+#endif
+ xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
+ sleep(1);
+#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
+#else
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2,
+ &temp);
+ if (temp & IEEE_AUTONEG_ERROR_MASK) {
+ xil_printf("Auto negotiation error \r\n");
+ }
+#endif
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
+ &status);
+ }
+
+ xil_printf("autonegotiation complete \r\n");
+
+#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
+#else
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_SPECIFIC_STATUS_REG, &partner_capabilities);
+#endif
+
+#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
+ xil_printf("Waiting for Link to be up; Polling for SGMII core Reg \r\n");
+ XEmacPs_PhyRead(xemacpsp, phy_addr, 5, &temp);
+ while(!(temp & 0x8000)) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, 5, &temp);
+ }
+ if((temp & 0x0C00) == 0x0800) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
+ return 1000;
+ }
+ else if((temp & 0x0C00) == 0x0400) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
+ return 100;
+ }
+ else if((temp & 0x0C00) == 0x0000) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
+ return 10;
+ } else {
+ xil_printf("get_IEEE_phy_speed(): Invalid speed bit value, Deafulting to Speed = 10 Mbps\r\n");
+ XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, 0, 0x0100);
+ return 10;
+ }
+#else
+ if ( ((partner_capabilities >> 14) & 3) == 2)/* 1000Mbps */
+ return 1000;
+ else if ( ((partner_capabilities >> 14) & 3) == 1)/* 100Mbps */
+ return 100;
+ else /* 10Mbps */
+ return 10;
+#endif
+}
+#endif
+
+unsigned configure_IEEE_phy_speed(XEmacPs *xemacpsp, unsigned speed)
+{
+ u16 control;
+ u32 phy_addr = detect_phy(xemacpsp);
+
+ XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
+ control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
+ control |= IEEE_ASYMMETRIC_PAUSE_MASK;
+ control |= IEEE_PAUSE_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control &= ~IEEE_CTRL_LINKSPEED_1000M;
+ control &= ~IEEE_CTRL_LINKSPEED_100M;
+ control &= ~IEEE_CTRL_LINKSPEED_10M;
+
+ if (speed == 1000) {
+ control |= IEEE_CTRL_LINKSPEED_1000M;
+ }
+
+ else if (speed == 100) {
+ control |= IEEE_CTRL_LINKSPEED_100M;
+ /* Dont advertise PHY speed of 1000 Mbps */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, 0);
+ /* Dont advertise PHY speed of 10 Mbps */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG,
+ ADVERTISE_100);
+ }
+
+ else if (speed == 10) {
+ control |= IEEE_CTRL_LINKSPEED_10M;
+ /* Dont advertise PHY speed of 1000 Mbps */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ 0);
+ /* Dont advertise PHY speed of 100 Mbps */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG,
+ ADVERTISE_10);
+ }
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET,
+ control | IEEE_CTRL_RESET_MASK);
+ {
+ volatile int wait;
+ for (wait=0; wait < 100000; wait++);
+ }
+ return 0;
+}
+
+static void SetUpSLCRDivisors(int mac_baseaddr, int speed)
+{
+ volatile u32 slcrBaseAddress;
+#ifndef PEEP
+ u32 SlcrDiv0;
+ u32 SlcrDiv1=0;
+ u32 SlcrTxClkCntrl;
+#endif
+
+ *(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE;
+
+ if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
+ slcrBaseAddress = SLCR_GEM0_CLK_CTRL_ADDR;
+ } else {
+ slcrBaseAddress = SLCR_GEM1_CLK_CTRL_ADDR;
+ }
+#ifdef PEEP
+ if (speed == 1000) {
+ *(volatile unsigned int *)(slcrBaseAddress) =
+ SLCR_GEM_1G_CLK_CTRL_VALUE;
+ } else if (speed == 100) {
+ *(volatile unsigned int *)(slcrBaseAddress) =
+ SLCR_GEM_100M_CLK_CTRL_VALUE;
+ } else {
+ *(volatile unsigned int *)(slcrBaseAddress) =
+ SLCR_GEM_10M_CLK_CTRL_VALUE;
+ }
+#else
+ if (speed == 1000) {
+ if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
+#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ } else {
+#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ }
+ } else if (speed == 100) {
+ if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
+#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1;
+#endif
+ } else {
+#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV1;
+#endif
+ }
+ } else {
+ if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
+#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1;
+#endif
+ } else {
+#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV1;
+#endif
+ }
+ }
+ SlcrTxClkCntrl = *(volatile unsigned int *)(slcrBaseAddress);
+ SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
+ SlcrTxClkCntrl |= (SlcrDiv1 << 20);
+ SlcrTxClkCntrl |= (SlcrDiv0 << 8);
+ *(volatile unsigned int *)(slcrBaseAddress) = SlcrTxClkCntrl;
+#endif
+ *(volatile unsigned int *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE;
+ return;
+}
+
+
+unsigned link_speed;
+unsigned Phy_Setup (XEmacPs *xemacpsp)
+{
+ unsigned long conv_present = 0;
+ unsigned long convspeeddupsetting = 0;
+ unsigned long convphyaddr = 0;
+
+#ifdef XPAR_GMII2RGMIICON_0N_ETH0_ADDR
+ convphyaddr = XPAR_GMII2RGMIICON_0N_ETH0_ADDR;
+ conv_present = 1;
+#else
+#ifdef XPAR_GMII2RGMIICON_0N_ETH1_ADDR
+ convphyaddr = XPAR_GMII2RGMIICON_0N_ETH1_ADDR;
+ conv_present = 1;
+#endif
+#endif
+
+#ifdef ipconfigNIC_LINKSPEED_AUTODETECT
+ link_speed = get_IEEE_phy_speed(xemacpsp);
+ if (link_speed == 1000) {
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
+ } else if (link_speed == 100) {
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
+ } else {
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
+ }
+#elif defined(ipconfigNIC_LINKSPEED1000)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
+ link_speed = 1000;
+ configure_IEEE_phy_speed(xemacpsp, link_speed);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
+ sleep(1);
+#elif defined(ipconfigNIC_LINKSPEED100)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
+ link_speed = 100;
+ configure_IEEE_phy_speed(xemacpsp, link_speed);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
+ sleep(1);
+#elif defined(ipconfigNIC_LINKSPEED10)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
+ link_speed = 10;
+ configure_IEEE_phy_speed(xemacpsp, link_speed);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
+ sleep(1);
+#endif
+ if (conv_present) {
+ XEmacPs_PhyWrite(xemacpsp, convphyaddr,
+ XEMACPS_GMII2RGMII_REG_NUM, convspeeddupsetting);
+ }
+
+ xil_printf("link speed: %d\r\n", link_speed);
+ return link_speed;
+}
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_topology.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_topology.h
new file mode 100644
index 000000000..bb5178346
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_topology.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007-2013 Xilinx, Inc. All rights reserved.
+ *
+ * Xilinx, Inc.
+ * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
+ * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
+ * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
+ * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
+ * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
+ * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
+ * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
+ * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
+ * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
+ * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef __XTOPOLOGY_H_
+#define __XTOPOLOGY_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum xemac_types { xemac_type_unknown = -1, xemac_type_xps_emaclite, xemac_type_xps_ll_temac, xemac_type_axi_ethernet, xemac_type_emacps };
+
+struct xtopology_t {
+ unsigned emac_baseaddr;
+ enum xemac_types emac_type;
+ unsigned intc_baseaddr;
+ unsigned intc_emac_intr; /* valid only for xemac_type_xps_emaclite */
+ unsigned scugic_baseaddr; /* valid only for Zynq */
+ unsigned scugic_emac_intr; /* valid only for GEM */
+};
+
+extern int x_topology_n_emacs;
+extern struct xtopology_t x_topology[];
+
+int x_topology_find_index(unsigned base);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c
new file mode 100644
index 000000000..5ed7ae846
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c
@@ -0,0 +1,1304 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.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 "NetworkBufferManagement.h"
+#include "NetworkInterface.h"
+
+#include "sam4e_xplained_pro.h"
+#include "hr_gettime.h"
+#include "conf_eth.h"
+#include "ksz8851snl.h"
+#include "ksz8851snl_reg.h"
+
+/* Some files from the Atmel Software Framework */
+#include <sysclk.h>
+#include <pdc/pdc.h>
+#include <spi/spi.h>
+
+/*
+ Sending a packet:
+
+ 1) Called by UP-task, add buffer to the TX-list:
+ xNetworkInterfaceOutput()
+ tx_buffers[ us_tx_head ] = pxNetworkBuffer;
+ tx_busy[ us_tx_head ] = pdTRUE;
+ us_tx_head++;
+
+ 2) Called by EMAC-Task: start SPI transfer
+ ksz8851snl_update()
+ if( ul_spi_pdc_status == SPI_PDC_IDLE )
+ {
+ if( ( tx_busy[ us_tx_tail ] != pdFALSE ) &&
+ ( us_pending_frame == 0 ) &&
+ ( ul_had_intn_interrupt == 0 ) )
+ {
+ // disable all interrupts.
+ ksz8851_reg_write( REG_INT_MASK, 0 );
+ Bring KSZ8851SNL_CSN_GPIO low
+ ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );
+ ul_spi_pdc_status = SPI_PDC_TX_START;
+ tx_cur_buffer = pxNetworkBuffer;
+ }
+ }
+ 3) Wait for SPI RXBUFF interrupt
+ SPI_Handler()
+ if( ul_spi_pdc_status == SPI_PDC_TX_START )
+ {
+ if( SPI_Status & SPI_SR_RXBUFF )
+ {
+ ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;
+ }
+ }
+
+ 4) Called by EMAC-Task: finish SPI transfer
+ ksz8851snl_update()
+ if( ul_spi_pdc_status == SPI_PDC_TX_COMPLETE )
+ {
+ ul_spi_pdc_status = SPI_PDC_IDLE;
+ Bring KSZ8851SNL_CSN_GPIO high
+ // TX step12: disable TXQ write access.
+ ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
+ // TX step12.1: enqueue frame in TXQ.
+ ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );
+
+ // RX step13: enable INT_RX flag.
+ ksz8851_reg_write( REG_INT_MASK, INT_RX );
+
+ // Buffer sent, free the corresponding buffer and mark descriptor as owned by software.
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+
+ tx_buffers[ us_tx_tail ] = NULL;
+ tx_busy[ us_tx_tail ] = pdFALSE;
+ us_tx_tail++
+ }
+
+ Receiving a packet:
+
+ 1) Wait for a INTN interrupt
+ INTN_Handler()
+ ul_had_intn_interrupt = 1
+ vTaskNotifyGiveFromISR(); // Wake up the EMAC task
+
+ 2) Called by EMAC-Task: check for new fragments and start SPI transfer
+ ksz8851snl_update()
+ if( ul_spi_pdc_status == SPI_PDC_IDLE )
+ {
+ if( ( ul_had_intn_interrupt != 0 ) || ( us_pending_frame > 0 ) )
+ {
+ if( us_pending_frame == 0 )
+ {
+ us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
+ if( us_pending_frame == 0 )
+ {
+ break;
+ }
+ }
+ // RX step2: disable all interrupts.
+ ksz8851_reg_write( REG_INT_MASK, 0 );
+ Check if there is a valid packet: REG_RX_FHR_STATUS
+ Read the length of the next fragment: REG_RX_FHR_BYTE_CNT
+ ul_spi_pdc_status = SPI_PDC_RX_START;
+ gpio_set_pin_low(KSZ8851SNL_CSN_GPIO);
+ // Start SPI data transfer
+ ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer, xReadLength );
+ }
+ }
+
+ 3) Wait for SPI RXBUFF interrupt
+ SPI_Handler()
+ if( ul_spi_pdc_status == SPI_PDC_RX_START:
+ {
+ if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )
+ {
+ // Transfer complete, disable SPI RXBUFF interrupt.
+ spi_disable_interrupt( KSZ8851SNL_SPI, SPI_IDR_RXBUFF );
+
+ ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;
+ }
+ }
+ }
+
+ 4) Finish SPI transfer
+ ksz8851snl_update()
+ if( ul_spi_pdc_status == SPI_PDC_RX_COMPLETE )
+ {
+ ul_spi_pdc_status = SPI_PDC_IDLE;
+ Bring KSZ8851SNL_CSN_GPIO high
+ // RX step21: end RXQ read access.
+ ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);
+ // RX step22-23: update frame count to be read.
+ us_pending_frame--
+ // RX step24: enable INT_RX flag if transfer complete.
+ if( us_pending_frame == 0 )
+ {
+ // Allow more RX interrupts.
+ ksz8851_reg_write( REG_INT_MASK, INT_RX );
+ }
+
+ // Mark descriptor ready to be read.
+ rx_ready[ rxHead ] = pdTRUE;
+ rxHead++
+ }
+*/
+
+#define PHY_REG_00_BMCR 0x00 // Basic mode control register
+#define PHY_REG_01_BMSR 0x01 // Basic mode status register
+#define PHY_REG_02_PHYSID1 0x02 // PHYS ID 1
+#define PHY_REG_03_PHYSID2 0x03 // PHYS ID 2
+#define PHY_REG_04_ADVERTISE 0x04 // Advertisement control reg
+#define PHY_REG_05_LPA 0x05 // Link partner ability reg
+#define PHY_REG_06_ANER 0x06 // 6 RW Auto-Negotiation Expansion Register
+#define PHY_REG_07_ANNPTR 0x07 // 7 RW Auto-Negotiation Next Page TX
+#define PHY_REG_08_RESERVED0 0x08 // 0x08..0x0Fh 8-15 RW RESERVED
+
+#define BMSR_LINK_STATUS 0x0004 //!< Link status
+
+#ifndef PHY_LS_HIGH_CHECK_TIME_MS
+ /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
+ receiving packets. */
+ #define PHY_LS_HIGH_CHECK_TIME_MS 15000
+#endif
+
+#ifndef PHY_LS_LOW_CHECK_TIME_MS
+ /* Check if the LinkSStatus in the PHY is still low every second. */
+ #define PHY_LS_LOW_CHECK_TIME_MS 1000
+#endif
+
+/* Interrupt events to process. Currently only the Rx event is processed
+although code for other events is included to allow for possible future
+expansion. */
+#define EMAC_IF_RX_EVENT 1UL
+#define EMAC_IF_TX_EVENT 2UL
+#define EMAC_IF_ERR_EVENT 4UL
+#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
+
+#define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
+
+#ifdef ipconfigHAS_TX_CRC_OFFLOADING
+ #undef ipconfigHAS_TX_CRC_OFFLOADING
+#endif
+/* Override this define because the KSZ8851 is programmed to set all outgoing CRC's */
+#define ipconfigHAS_TX_CRC_OFFLOADING 1
+
+#ifndef EMAC_MAX_BLOCK_TIME_MS
+ #define EMAC_MAX_BLOCK_TIME_MS 100ul
+#endif
+
+/* Default the size of the stack used by the EMAC deferred handler task to 4x
+the size of the stack used by the idle task - but allow this to be overridden in
+FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
+#ifndef configEMAC_TASK_STACK_SIZE
+ #define configEMAC_TASK_STACK_SIZE ( 6 * configMINIMAL_STACK_SIZE )
+#endif
+
+#define SPI_PDC_IDLE 0
+#define SPI_PDC_RX_START 1
+#define SPI_PDC_TX_ERROR 2
+#define SPI_PDC_RX_COMPLETE 3
+#define SPI_PDC_TX_START 4
+#define SPI_PDC_RX_ERROR 5
+#define SPI_PDC_TX_COMPLETE 6
+
+/**
+ * ksz8851snl driver structure.
+ */
+typedef struct {
+ /** Set to 1 when owner is software (ready to read), 0 for Micrel. */
+ uint32_t rx_ready[MICREL_RX_BUFFERS];
+ /** Set to 1 when owner is Micrel, 0 for software. */
+ uint32_t tx_busy[MICREL_TX_BUFFERS];
+ /** RX NetworkBufferDescriptor_t pointer list */
+ NetworkBufferDescriptor_t *rx_buffers[MICREL_RX_BUFFERS];
+ /** TX NetworkBufferDescriptor_t pointer list */
+ NetworkBufferDescriptor_t *tx_buffers[MICREL_TX_BUFFERS];
+ NetworkBufferDescriptor_t *tx_cur_buffer;
+
+ /** Circular buffer head pointer for packet received. */
+ uint32_t us_rx_head;
+ /** Circular buffer tail pointer for packet to be read. */
+ uint32_t us_rx_tail;
+ /** Circular buffer head pointer by upper layer (buffer to be sent). */
+ uint32_t us_tx_head;
+ /** Circular buffer tail pointer incremented by handlers (buffer sent). */
+ uint32_t us_tx_tail;
+
+ uint32_t ul_total_tx;
+ uint32_t ul_total_rx;
+ uint32_t tx_space;
+
+ /** Still experimental: hash table to allow certain multicast addresses. */
+ uint16_t pusHashTable[ 4 ];
+
+ /* ul_spi_pdc_status has "SPI_PDC_xxx" values. */
+ volatile uint32_t ul_spi_pdc_status;
+
+ /* ul_had_intn_interrupt becomes true within the INTN interrupt. */
+ volatile uint32_t ul_had_intn_interrupt;
+
+ uint16_t us_pending_frame;
+} xKSZ8851_Device_t;
+
+/* SPI PDC register base.
+Declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */
+extern Pdc *g_p_spi_pdc;
+
+/* Temporary buffer for PDC reception.
+declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */
+extern uint8_t tmpbuf[1536];
+
+COMPILER_ALIGNED(8)
+static xKSZ8851_Device_t xMicrelDevice;
+
+static TaskHandle_t xTransmitHandle;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Wait a fixed time for the link status to indicate the network is up.
+ */
+static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
+
+/*
+ * A deferred interrupt handler task that processes GMAC interrupts.
+ */
+static void prvEMACHandlerTask( void *pvParameters );
+
+/*
+ * Try to obtain an Rx packet from the hardware.
+ */
+static uint32_t prvEMACRxPoll( void );
+
+static inline unsigned long ulReadMDIO( unsigned uAddress );
+
+static void ksz8851snl_low_level_init( void );
+
+static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void );
+
+/*-----------------------------------------------------------*/
+
+/* Bit map of outstanding ETH interrupt events for processing. Currently only
+the Rx interrupt is handled, although code is included for other events to
+enable future expansion. */
+static volatile uint32_t ulISREvents;
+
+/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
+static uint32_t ulPHYLinkStatus = 0;
+static volatile BaseType_t xGMACSwitchRequired;
+
+static void ksz8851snl_update( void );
+
+static void ksz8851snl_rx_init( void );
+
+static void ksz8851snl_tx_init( void );
+
+/* Holds the handle of the task used as a deferred interrupt processor. The
+handle is used so direct notifications can be sent to the task for all EMAC/DMA
+related interrupts. */
+TaskHandle_t xEMACTaskHandle = NULL;
+
+
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceInitialise( void )
+{
+const TickType_t x5_Seconds = 5000UL;
+
+ if( xEMACTaskHandle == NULL )
+ {
+ ksz8851snl_low_level_init();
+
+ /* Wait at most 5 seconds for a Link Status in the PHY. */
+ xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
+
+ /* The handler task is created at the highest possible priority to
+ ensure the interrupt handler can return directly to it. */
+ xTaskCreate( prvEMACHandlerTask, "KSZ8851", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
+ configASSERT( xEMACTaskHandle );
+ }
+
+ /* When returning non-zero, the stack will become active and
+ start DHCP (in configured) */
+ ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
+
+ return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xGetPhyLinkStatus( void )
+{
+BaseType_t xResult;
+
+ /* This function returns true if the Link Status in the PHY is high. */
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ xResult = pdTRUE;
+ }
+ else
+ {
+ xResult = pdFALSE;
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t bReleaseAfterSend )
+{
+BaseType_t xResult = pdFALSE;
+int txHead = xMicrelDevice.us_tx_head;
+
+ /* Make sure the next descriptor is free. */
+ if( xMicrelDevice.tx_busy[ txHead ] != pdFALSE )
+ {
+ /* All TX buffers busy. */
+ }
+ else if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
+ {
+ /* Output: LS low. */
+ }
+ else
+ {
+ /* Pass the packet. */
+ xMicrelDevice.tx_buffers[ txHead ] = pxNetworkBuffer;
+ /* The descriptor is now owned by Micrel. */
+ xMicrelDevice.tx_busy[ txHead ] = pdTRUE;
+
+ /* Move the head pointer. */
+ if( ++txHead == MICREL_TX_BUFFERS )
+ {
+ txHead = 0;
+ }
+ xMicrelDevice.us_tx_head = txHead;
+ if( xEMACTaskHandle != NULL )
+ {
+ xTaskNotifyGive( xEMACTaskHandle );
+ }
+
+ #if( ipconfigZERO_COPY_TX_DRIVER != 1 )
+ #warning Please ipconfigZERO_COPY_TX_DRIVER as 1
+ #endif
+ configASSERT( bReleaseAfterSend != pdFALSE );
+ xResult = pdTRUE;
+ }
+ if( ( xResult == pdFALSE ) && ( bReleaseAfterSend != pdFALSE ) )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ }
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+/* This Micrel has numbered it's PHY registers in a different way.
+Translate the register index. */
+static int ks8851_phy_reg( int reg )
+{
+ switch (reg) {
+ case PHY_REG_00_BMCR:
+ return REG_PHY_CNTL; // P1MBCR;
+ case PHY_REG_01_BMSR:
+ return REG_PHY_STATUS;
+ case PHY_REG_02_PHYSID1:
+ return REG_PHY_ID_LOW;
+ case PHY_REG_03_PHYSID2:
+ return REG_PHY_ID_HIGH;
+ case PHY_REG_04_ADVERTISE:
+ return REG_PHY_AUTO_NEGOTIATION;
+ case PHY_REG_05_LPA:
+ return REG_PHY_REMOTE_CAPABILITY;
+ }
+
+ return 0x0;
+}
+/*-----------------------------------------------------------*/
+
+static inline unsigned long ulReadMDIO( unsigned uAddress )
+{
+uint16_t usPHYStatus;
+int ks8851_reg = ks8851_phy_reg( uAddress );
+
+ if( ks8851_reg != 0 )
+ {
+ usPHYStatus = ksz8851_reg_read( ks8851_reg );
+ }
+ else
+ {
+ /* Other addresses not yet implemented. */
+ usPHYStatus = 0;
+ }
+ return usPHYStatus;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
+{
+TickType_t xStartTime = xTaskGetTickCount();
+TickType_t xEndTime;
+BaseType_t xReturn;
+const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
+const uint32_t ulHz_Per_MHz = 1000000UL;
+
+ for( ;; )
+ {
+ xEndTime = xTaskGetTickCount();
+
+ if( ( xEndTime - xStartTime ) > xMaxTime )
+ {
+ /* Wated more than xMaxTime, return. */
+ xReturn = pdFALSE;
+ break;
+ }
+
+ /* Check the link status again. */
+ ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
+
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ /* Link is up - return. */
+ xReturn = pdTRUE;
+ break;
+ }
+
+ /* Link is down - wait in the Blocked state for a short while (to allow
+ other tasks to execute) before checking again. */
+ vTaskDelay( xShortTime );
+ }
+
+ FreeRTOS_printf( ( "xGMACWaitLS: %ld freq %lu Mz\n",
+ xReturn,
+ sysclk_get_cpu_hz() / ulHz_Per_MHz ) );
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static void vPioSetPinHigh(uint32_t ul_pin)
+{
+ Pio *p_pio = (Pio *)((uint32_t)PIOA + (PIO_DELTA * (ul_pin >> 5)));
+ // Value to be driven on the I/O line: 1.
+ p_pio->PIO_SODR = 1 << (ul_pin & 0x1F);
+}
+
+/**
+ * \brief Handler for SPI interrupt.
+ */
+void SPI_Handler(void)
+{
+BaseType_t xDoWakeup = pdFALSE;
+BaseType_t xKSZTaskWoken = pdFALSE;
+uint32_t ulCurrentSPIStatus;
+uint32_t ulEnabledSPIStatus;
+
+ ulCurrentSPIStatus = spi_read_status( KSZ8851SNL_SPI );
+ ulEnabledSPIStatus = spi_read_interrupt_mask( KSZ8851SNL_SPI );
+ ulCurrentSPIStatus &= ulEnabledSPIStatus;
+ spi_disable_interrupt( KSZ8851SNL_SPI, ulCurrentSPIStatus );
+
+
+ switch( xMicrelDevice.ul_spi_pdc_status )
+ {
+ case SPI_PDC_RX_START:
+ {
+ if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )
+ {
+ pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
+ xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_ERROR;
+ xDoWakeup = pdTRUE;
+ }
+ else
+ {
+ if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )
+ {
+ xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;
+ xDoWakeup = pdTRUE;
+ }
+ }
+ }
+ break;
+
+ case SPI_PDC_TX_START:
+ {
+ /* Middle of TX. */
+ if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )
+ {
+ pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
+ xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_ERROR;
+ xDoWakeup = pdTRUE;
+ }
+ else
+ {
+ if( ( ulCurrentSPIStatus & SPI_SR_ENDRX ) != 0 )
+ {
+ /* Enable RX complete interrupt. */
+ spi_enable_interrupt( KSZ8851SNL_SPI, SPI_IER_RXBUFF );
+ }
+ /* End of TX. */
+ if( ( ulCurrentSPIStatus & SPI_END_OF_TX ) != 0 )
+ {
+ xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;
+ xDoWakeup = pdTRUE;
+ }
+ }
+ }
+ break;
+ } /* switch( xMicrelDevice.ul_spi_pdc_status ) */
+
+ if( xDoWakeup != pdFALSE )
+ {
+ if( xEMACTaskHandle != NULL )
+ {
+ vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xKSZTaskWoken );
+ }
+ }
+ else
+ {
+ }
+ portEND_SWITCHING_ISR( xKSZTaskWoken );
+}
+/*-----------------------------------------------------------*/
+
+static void INTN_Handler(uint32_t id, uint32_t mask)
+{
+BaseType_t xKSZTaskWoken = pdFALSE;
+
+ if( ( id == INTN_ID ) &&
+ ( mask == INTN_PIN_MSK ) )
+ {
+ /* Clear the PIO interrupt flags. */
+ pio_get_interrupt_status( INTN_PIO );
+
+ /* Set the INTN flag. */
+ xMicrelDevice.ul_had_intn_interrupt++;
+ if( xEMACTaskHandle != NULL )
+ {
+ vTaskNotifyGiveFromISR( xEMACTaskHandle, &( xKSZTaskWoken ) );
+ }
+ }
+ portEND_SWITCHING_ISR( xKSZTaskWoken );
+}
+/*-----------------------------------------------------------*/
+
+/**
+ * \brief Populate the RX descriptor ring buffers with pbufs.
+ *
+ * \param p_ksz8851snl_dev Pointer to driver data structure.
+ */
+static void ksz8851snl_rx_populate_queue( void )
+{
+ uint32_t ul_index = 0;
+ NetworkBufferDescriptor_t *pxNetworkBuffer;
+
+ /* Set up the RX descriptors */
+ for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {
+ if( xMicrelDevice.rx_buffers[ ul_index ] == NULL )
+ {
+ /* Allocate a new NetworkBufferDescriptor_t with the maximum size. */
+ pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipconfigNETWORK_MTU + 36, 100 );
+ if( pxNetworkBuffer == NULL )
+ {
+ FreeRTOS_printf( ( "ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t allocation failure\n" ) );
+ configASSERT( 1 == 2 );
+ }
+
+ /* Make sure lwIP is well configured so one NetworkBufferDescriptor_t can contain the maximum packet size. */
+ //LWIP_ASSERT("ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t size too small!", pbuf_clen(pxNetworkBuffer) <= 1);
+
+ /* Save NetworkBufferDescriptor_t pointer to be sent to lwIP upper layer. */
+ xMicrelDevice.rx_buffers[ ul_index ] = pxNetworkBuffer;
+ /* Pass it to Micrel for reception. */
+ xMicrelDevice.rx_ready[ ul_index ] = pdFALSE;
+ }
+ }
+}
+
+unsigned tx_space, wait_tx_space, tx_status, fhr_status;
+unsigned rx_debug = 0;
+/**
+ * \brief Update Micrel state machine and perform required actions.
+ *
+ * \param netif the lwIP network interface structure for this ethernetif.
+ */
+static void ksz8851snl_update()
+{
+ uint16_t txmir = 0;
+
+/* Check for free PDC. */
+ switch( xMicrelDevice.ul_spi_pdc_status )
+ {
+ case SPI_PDC_TX_ERROR:
+ {
+ uint32_t ulValue;
+ // /* TX step11: end TX transfer. */
+ gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
+
+ vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
+ vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
+ vTaskDelay( 1 );
+
+ /* Disable asynchronous transfer mode. */
+ xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
+
+ /* TX step12: disable TXQ write access. */
+ ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
+
+ ulValue = ksz8851snl_reset_tx();
+
+ xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;
+
+ FreeRTOS_printf( ("SPI_PDC_TX_ERROR %02X\n", ulValue ) );
+ }
+ break;
+
+ case SPI_PDC_RX_ERROR:
+ {
+ uint32_t ulValue;
+ /* TX step11: end TX transfer. */
+ gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
+
+ vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
+ vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
+ vTaskDelay( 1 );
+
+ /* Disable asynchronous transfer mode. */
+ xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
+
+ /* TX step12: disable TXQ write access. */
+ ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
+
+ //ulValue = ksz8851snl_reset_rx();
+ ulValue = ksz8851snl_reinit();
+
+ xGMACWaitLS( pdMS_TO_TICKS( 5000UL ) );
+
+ FreeRTOS_printf( ("SPI_PDC_RX_ERROR %02X\n", ulValue ) );
+ }
+ break;
+ }
+ switch( xMicrelDevice.ul_spi_pdc_status )
+ {
+ case SPI_PDC_IDLE:
+ {
+ int txTail = xMicrelDevice.us_tx_tail;
+
+ /*
+ * ========================== Handle RX ==========================
+ */
+ if( ( xMicrelDevice.ul_had_intn_interrupt != 0 ) || ( xMicrelDevice.us_pending_frame > 0 ) )
+ {
+ int rxHead = xMicrelDevice.us_rx_head;
+ NetworkBufferDescriptor_t *pxNetworkBuffer;
+#warning try
+ xMicrelDevice.ul_had_intn_interrupt = 0;
+
+ if( xMicrelDevice.us_pending_frame == 0 )
+ {
+ uint16_t int_status;
+ /* RX step1: read interrupt status for INT_RX flag. */
+ int_status = ksz8851_reg_read( REG_INT_STATUS );
+
+
+ /* RX step2: disable all interrupts. */
+ ksz8851_reg_write( REG_INT_MASK, 0 );
+
+ /* RX step3: clear INT_RX flag. */
+ ksz8851_reg_setbits( REG_INT_STATUS, INT_RX );
+
+ /* RX step4-5: check for received frames. */
+ xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
+ if( xMicrelDevice.us_pending_frame == 0 )
+ {
+ /* RX step24: enable INT_RX flag. */
+ ksz8851_reg_write(REG_INT_MASK, INT_RX);
+ return;
+ }
+ }
+#warning try
+ xMicrelDevice.ul_had_intn_interrupt = 0;
+
+ /* Now xMicrelDevice.us_pending_frame != 0 */
+
+ /* Don't break Micrel state machine, wait for a free descriptor first! */
+ if( xMicrelDevice.rx_ready[ rxHead ] != pdFALSE )
+ {
+ FreeRTOS_printf( ( "ksz8851snl_update: out of free descriptor! [tail=%u head=%u]\n",
+ xMicrelDevice.us_rx_tail, rxHead ) );
+ return;
+ }
+ pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxHead ];
+
+ if( pxNetworkBuffer == NULL )
+ {
+ ksz8851snl_rx_populate_queue();
+ FreeRTOS_printf( ( "ksz8851snl_update: no buffer set [head=%u]\n", rxHead ) );
+ return;
+ }
+
+ /* RX step6: get RX packet status. */
+ fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );
+ if( ( ( fhr_status & RX_VALID ) == 0 ) || ( ( fhr_status & RX_ERRORS ) != 0 ) )
+ {
+ ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_CMD_FREE_PACKET);
+ FreeRTOS_printf( ( "ksz8851snl_update: RX packet error!\n" ) );
+
+ /* RX step4-5: check for received frames. */
+ xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
+ if( xMicrelDevice.us_pending_frame == 0 )
+ {
+ /* RX step24: enable INT_RX flag. */
+ ksz8851_reg_write(REG_INT_MASK, INT_RX);
+ }
+ ulISREvents |= EMAC_IF_ERR_EVENT;
+ }
+ else
+ {
+ size_t xLength;
+ /* RX step7: read frame length. */
+ xLength = ksz8851_reg_read(REG_RX_FHR_BYTE_CNT) & RX_BYTE_CNT_MASK;
+
+ /* RX step8: Drop packet if len is invalid or no descriptor available. */
+ if( xLength == 0 )
+ {
+ ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_CMD_FREE_PACKET );
+ FreeRTOS_printf( ( "ksz8851snl_update: RX bad len!\n" ) );
+ ulISREvents |= EMAC_IF_ERR_EVENT;
+ }
+ else
+ {
+ size_t xReadLength = xLength;
+
+ xMicrelDevice.ul_total_rx++;
+ /* RX step9: reset RX frame pointer. */
+ ksz8851_reg_clrbits(REG_RX_ADDR_PTR, ADDR_PTR_MASK);
+
+ /* RX step10: start RXQ read access. */
+ ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_START);
+ /* RX step11-17: start asynchronous FIFO read operation. */
+ xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_START;
+ gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
+ if( ( xReadLength & ( sizeof( size_t ) - 1 ) ) != 0 )
+ {
+ xReadLength = ( xReadLength | ( sizeof( size_t ) - 1 ) ) + 1;
+ }
+
+ /* Pass the buffer minus 2 bytes, see ksz8851snl.c: RXQ_TWOBYTE_OFFSET. */
+ ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer - 2, xReadLength );
+ /* Remove CRC and update buffer length. */
+ xLength -= 4;
+ pxNetworkBuffer->xDataLength = xLength;
+ /* Wait for SPI interrupt to set status 'SPI_PDC_RX_COMPLETE'. */
+ }
+ }
+ break;
+ } /* ul_had_intn_interrupt || us_pending_frame */
+ /*
+ * ========================== Handle TX ==========================
+ */
+
+ /* Fetch next packet to be sent. */
+ if( ( xMicrelDevice.tx_busy[ txTail ] != pdFALSE ) &&
+ ( xMicrelDevice.us_pending_frame == 0 ) &&
+ ( xMicrelDevice.ul_had_intn_interrupt == 0 ) )
+ {
+ NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];
+ size_t xLength = pxNetworkBuffer->xDataLength;
+ int iIndex = xLength;
+
+ xLength = 4 * ( ( xLength + 3 ) / 4 );
+ while( iIndex < ( int ) xLength )
+ {
+ pxNetworkBuffer->pucEthernetBuffer[ iIndex ] = '\0';
+ iIndex++;
+ }
+ pxNetworkBuffer->xDataLength = xLength;
+
+ /* TX step1: check if TXQ memory size is available for transmit. */
+ txmir = ksz8851_reg_read( REG_TX_MEM_INFO );
+ txmir = txmir & TX_MEM_AVAILABLE_MASK;
+
+ if( txmir < ( xLength + 8 ) )
+ {
+ if( wait_tx_space == pdFALSE )
+ {
+ tx_status = ksz8851_reg_read( REG_TX_STATUS );
+ fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );
+ wait_tx_space = pdTRUE;
+ }
+ //return;
+ rx_debug = 1;
+ tx_space = txmir;
+ }
+ else
+ {
+ tx_space = txmir;
+
+ /* TX step2: disable all interrupts. */
+ ksz8851_reg_write( REG_INT_MASK, 0 );
+
+ xMicrelDevice.tx_space -= xLength;
+
+ /* TX step3: enable TXQ write access. */
+ ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_START );
+ /* TX step4-8: perform FIFO write operation. */
+ xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_START;
+ xMicrelDevice.tx_cur_buffer = pxNetworkBuffer;
+ /* Bring SPI SS low. */
+ gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
+ xMicrelDevice.ul_total_tx++;
+
+ ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );
+ }
+ }
+ }
+ break; /* SPI_PDC_IDLE */
+
+ case SPI_PDC_RX_COMPLETE:
+ {
+ int rxHead = xMicrelDevice.us_rx_head;
+ /* RX step18-19: pad with dummy data to keep dword alignment. */
+ /* Packet lengths will be rounded up to a multiple of "sizeof size_t". */
+// xLength = xMicrelDevice.rx_buffers[ rxHead ]->xDataLength & 3;
+// if( xLength != 0 )
+// {
+// ksz8851_fifo_dummy( 4 - xLength );
+// }
+
+ /* RX step20: end RX transfer. */
+ gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
+
+ /* Disable asynchronous transfer mode. */
+ xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
+
+ /* RX step21: end RXQ read access. */
+ ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);
+
+ /* RX step22-23: update frame count to be read. */
+ xMicrelDevice.us_pending_frame -= 1;
+
+ /* RX step24: enable INT_RX flag if transfer complete. */
+ if( xMicrelDevice.us_pending_frame == 0 )
+ {
+ ksz8851_reg_write(REG_INT_MASK, INT_RX);
+ }
+
+ /* Mark descriptor ready to be read. */
+ xMicrelDevice.rx_ready[ rxHead ] = pdTRUE;
+ if( ++rxHead == MICREL_RX_BUFFERS )
+ {
+ rxHead = 0;
+ }
+ xMicrelDevice.us_rx_head = rxHead;
+ if( rx_debug != 0 )
+ {
+ uint32_t txmir;
+ rx_debug = 0;
+ txmir = ksz8851_reg_read( REG_TX_MEM_INFO );
+ txmir = txmir & TX_MEM_AVAILABLE_MASK;
+ }
+ /* Tell prvEMACHandlerTask that RX packets are available. */
+ ulISREvents |= EMAC_IF_RX_EVENT;
+ } /* case SPI_PDC_RX_COMPLETE */
+ break;
+
+ case SPI_PDC_TX_COMPLETE:
+ {
+ int txTail = xMicrelDevice.us_tx_tail;
+ NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];
+
+ size_t xLength;
+ /* TX step9-10: pad with dummy data to keep dword alignment. */
+ /* Not necessary: length is already a multiple of 4. */
+ xLength = pxNetworkBuffer->xDataLength & 3;
+ if( xLength != 0 )
+ {
+// ksz8851_fifo_dummy( 4 - xLength );
+ }
+
+// /* TX step11: end TX transfer. */
+ gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
+
+ /* Disable asynchronous transfer mode. */
+ xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
+
+ /* TX step12: disable TXQ write access. */
+ ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
+
+ xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;
+
+ /* TX step12.1: enqueue frame in TXQ. */
+ ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );
+
+ /* RX step13: enable INT_RX flag. */
+// ksz8851_reg_write( REG_INT_MASK, INT_RX );
+ /* Buffer sent, free the corresponding buffer and mark descriptor as owned by software. */
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+
+ xMicrelDevice.tx_buffers[ txTail ] = NULL;
+ xMicrelDevice.tx_busy[ txTail ] = pdFALSE;
+ if( ++txTail == MICREL_TX_BUFFERS )
+ {
+ txTail = 0;
+ }
+
+ xMicrelDevice.us_tx_tail = txTail;
+ /* Experiment. */
+ //xMicrelDevice.ul_had_intn_interrupt = 1;
+ if( xTransmitHandle != NULL )
+ {
+ xTaskNotifyGive( xTransmitHandle );
+ }
+#warning moved downward
+ /* RX step13: enable INT_RX flag. */
+ ksz8851_reg_write( REG_INT_MASK, INT_RX );
+ /* Prevent the EMAC task from sleeping a single time. */
+ ulISREvents |= EMAC_IF_TX_EVENT;
+ } /* case SPI_PDC_TX_COMPLETE */
+ break;
+ } /* switch( xMicrelDevice.ul_spi_pdc_status ) */
+}
+
+/**
+ * \brief Set up the RX descriptor ring buffers.
+ *
+ * This function sets up the descriptor list used for RX packets.
+ *
+ */
+static void ksz8851snl_rx_init()
+{
+ uint32_t ul_index = 0;
+
+ /* Init pointer index. */
+ xMicrelDevice.us_rx_head = 0;
+ xMicrelDevice.us_rx_tail = 0;
+
+ /* Set up the RX descriptors. */
+ for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {
+ xMicrelDevice.rx_buffers[ul_index] = NULL;
+ xMicrelDevice.rx_ready[ul_index] = pdFALSE;
+ }
+
+ /* Build RX buffer and descriptors. */
+ ksz8851snl_rx_populate_queue();
+}
+
+/**
+ * \brief Set up the TX descriptor ring buffers.
+ *
+ * This function sets up the descriptor list used for TX packets.
+ *
+ */
+static void ksz8851snl_tx_init()
+{
+ uint32_t ul_index = 0;
+
+ /* Init TX index pointer. */
+ xMicrelDevice.us_tx_head = 0;
+ xMicrelDevice.us_tx_tail = 0;
+
+ /* Set up the TX descriptors */
+ for( ul_index = 0; ul_index < MICREL_TX_BUFFERS; ul_index++ )
+ {
+ xMicrelDevice.tx_busy[ul_index] = pdFALSE;
+ }
+ xMicrelDevice.tx_space = 6144;
+}
+
+/**
+ * \brief Initialize ksz8851snl ethernet controller.
+ *
+ * \note Called from ethernetif_init().
+ *
+ * \param netif the lwIP network interface structure for this ethernetif.
+ */
+static void ksz8851snl_low_level_init( void )
+{
+ ksz8851snl_rx_init();
+ ksz8851snl_tx_init();
+
+ /* Enable NVIC interrupts. */
+ NVIC_SetPriority(SPI_IRQn, INT_PRIORITY_SPI);
+ NVIC_EnableIRQ(SPI_IRQn);
+
+ /* Initialize SPI link. */
+ if( ksz8851snl_init() < 0 )
+ {
+ FreeRTOS_printf( ( "ksz8851snl_low_level_init: failed to initialize the Micrel driver!\n" ) );
+ configASSERT(0 == 1);
+ }
+ memset( xMicrelDevice.pusHashTable, 255, sizeof( xMicrelDevice.pusHashTable ) );
+ ksz8851_reg_write( REG_MAC_HASH_0, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 0 ] ) );
+ ksz8851_reg_write( REG_MAC_HASH_2, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 1 ] ) );
+ ksz8851_reg_write( REG_MAC_HASH_4, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 2 ] ) );
+ ksz8851_reg_write( REG_MAC_HASH_6, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 3 ] ) );
+
+ /* Initialize interrupt line INTN. */
+ configure_intn( INTN_Handler );
+}
+
+/**
+ * \brief Use pre-allocated pbuf as DMA source and return the incoming packet.
+ *
+ * \param netif the lwIP network interface structure for this ethernetif.
+ *
+ * \return a pbuf filled with the received packet (including MAC header).
+ * 0 on memory error.
+ */
+static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void )
+{
+NetworkBufferDescriptor_t *pxNetworkBuffer = NULL;
+int rxTail = xMicrelDevice.us_rx_tail;
+
+ /* Check that descriptor is owned by software (ie packet received). */
+ if( xMicrelDevice.rx_ready[ rxTail ] != pdFALSE )
+ {
+
+ /* Fetch pre-allocated buffer */
+ pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxTail ];
+
+ /* Remove this pbuf from its descriptor. */
+ xMicrelDevice.rx_buffers[ rxTail ] = NULL;
+
+ /* Clears rx_ready and sets rx_buffers. */
+ ksz8851snl_rx_populate_queue();
+
+ if( ++rxTail == MICREL_RX_BUFFERS )
+ {
+ rxTail = 0;
+ }
+ xMicrelDevice.us_rx_tail = rxTail;
+ }
+
+ return pxNetworkBuffer;
+}
+/*-----------------------------------------------------------*/
+
+static uint32_t prvEMACRxPoll( void )
+{
+NetworkBufferDescriptor_t *pxNetworkBuffer;
+IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
+uint32_t ulReturnValue = 0;
+
+ for( ;; )
+ {
+ /* Only for logging. */
+ int rxTail = xMicrelDevice.us_rx_tail;
+ EthernetHeader_t *pxEthernetHeader;
+
+ pxNetworkBuffer = ksz8851snl_low_level_input();
+
+ if( pxNetworkBuffer == NULL )
+ {
+ break;
+ }
+ pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
+
+ if( ( pxEthernetHeader->usFrameType != ipIPv4_FRAME_TYPE ) &&
+ ( pxEthernetHeader->usFrameType != ipARP_FRAME_TYPE ) )
+ {
+ FreeRTOS_printf( ( "Frame type %02X received\n", pxEthernetHeader->usFrameType ) );
+ }
+ ulReturnValue++;
+
+ xRxEvent.pvData = ( void * )pxNetworkBuffer;
+ /* Send the descriptor to the IP task for processing. */
+ if( xSendEventStructToIPTask( &xRxEvent, 100UL ) != pdTRUE )
+ {
+ vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+ iptraceETHERNET_RX_EVENT_LOST();
+ FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
+ }
+ }
+
+ return ulReturnValue;
+}
+/*-----------------------------------------------------------*/
+
+static void prvEMACHandlerTask( void *pvParameters )
+{
+TimeOut_t xPhyTime;
+TickType_t xPhyRemTime;
+TickType_t xLoggingTime;
+UBaseType_t uxLastMinBufferCount = 0;
+UBaseType_t uxCurrentCount;
+BaseType_t xResult = 0;
+uint32_t xStatus;
+const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
+#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+ UBaseType_t uxLastMinQueueSpace = 0;
+#endif
+
+ /* Remove compiler warnings about unused parameters. */
+ ( void ) pvParameters;
+
+ configASSERT( xEMACTaskHandle );
+
+ vTaskSetTimeOutState( &xPhyTime );
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+ xLoggingTime = xTaskGetTickCount();
+
+ for( ;; )
+ {
+ uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
+ if( uxLastMinBufferCount != uxCurrentCount )
+ {
+ /* The logging produced below may be helpful
+ while tuning +TCP: see how many buffers are in use. */
+ uxLastMinBufferCount = uxCurrentCount;
+ FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
+ uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
+ }
+
+ #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+ {
+ uxCurrentCount = uxGetMinimumIPQueueSpace();
+ if( uxLastMinQueueSpace != uxCurrentCount )
+ {
+ /* The logging produced below may be helpful
+ while tuning +TCP: see how many buffers are in use. */
+ uxLastMinQueueSpace = uxCurrentCount;
+ FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
+ }
+ }
+ #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
+
+ /* Run the state-machine of the ksz8851 driver. */
+ ksz8851snl_update();
+
+ if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
+ {
+ /* No events to process now, wait for the next. */
+ ulTaskNotifyTake( pdTRUE, ulMaxBlockTime );
+ }
+
+ if( ( xTaskGetTickCount() - xLoggingTime ) > 10000 )
+ {
+ xLoggingTime += 10000;
+ FreeRTOS_printf( ( "Now Tx/Rx %7d /%7d\n",
+ xMicrelDevice.ul_total_tx, xMicrelDevice.ul_total_rx ) );
+ }
+
+ if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
+ {
+ ulISREvents &= ~EMAC_IF_RX_EVENT;
+
+ /* Wait for the EMAC interrupt to indicate that another packet has been
+ received. */
+ xResult = prvEMACRxPoll();
+ }
+
+ if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
+ {
+ /* Future extension: code to release TX buffers if zero-copy is used. */
+ ulISREvents &= ~EMAC_IF_TX_EVENT;
+ }
+
+ if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
+ {
+ /* Future extension: logging about errors that occurred. */
+ ulISREvents &= ~EMAC_IF_ERR_EVENT;
+ }
+
+ if( xResult > 0 )
+ {
+ /* As long as packets are being received, assume that
+ the Link Status is high. */
+ ulPHYLinkStatus |= BMSR_LINK_STATUS;
+ /* A packet was received. No need to check for the PHY status now,
+ but set a timer to check it later on. */
+ vTaskSetTimeOutState( &xPhyTime );
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+ xResult = 0;
+ }
+ else if( ( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) &&
+ ( xMicrelDevice.ul_spi_pdc_status == SPI_PDC_IDLE ) )
+ {
+ /* Check the link status again. */
+ xStatus = ulReadMDIO( PHY_REG_01_BMSR );
+
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
+ {
+ ulPHYLinkStatus = xStatus;
+ FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
+ }
+
+ vTaskSetTimeOutState( &xPhyTime );
+ if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+ }
+ else
+ {
+ xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/Common/FreeRTOS_TCP_server.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/Common/FreeRTOS_TCP_server.c
new file mode 100644
index 000000000..0e7a7af39
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/Common/FreeRTOS_TCP_server.c
@@ -0,0 +1,382 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_TCP_server.h"
+#include "FreeRTOS_server_private.h"
+
+/* Remove the entire file if TCP is not being used. */
+#if( ipconfigUSE_TCP == 1 )
+
+#if !defined( ARRAY_SIZE )
+ #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] )
+#endif
+
+
+static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket );
+static char *strnew( const char *pcString );
+/* Remove slashes at the end of a path. */
+static void prvRemoveSlash( char *pcDir );
+
+TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount )
+{
+TCPServer_t *pxServer;
+SocketSet_t xSocketSet;
+
+ /* Create a new server.
+ xPort / xPortAlt : Make the service available on 1 or 2 public port numbers. */
+ xSocketSet = FreeRTOS_CreateSocketSet();
+
+ if( xSocketSet != NULL )
+ {
+ BaseType_t xSize;
+
+ xSize = sizeof( *pxServer ) - sizeof( pxServer->xServers ) + xCount * sizeof( pxServer->xServers[ 0 ] );
+
+ pxServer = ( TCPServer_t * ) pvPortMallocLarge( xSize );
+ if( pxServer != NULL )
+ {
+ struct freertos_sockaddr xAddress;
+ BaseType_t xNoTimeout = 0;
+ BaseType_t xIndex;
+
+ memset( pxServer, '\0', xSize );
+ pxServer->xServerCount = xCount;
+ pxServer->xSocketSet = xSocketSet;
+
+ for( xIndex = 0; xIndex < xCount; xIndex++ )
+ {
+ BaseType_t xPortNumber = pxConfigs[ xIndex ].xPortNumber;
+
+ if( xPortNumber > 0 )
+ {
+ Socket_t xSocket;
+
+ xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
+ FreeRTOS_printf( ( "TCP socket on port %d\n", ( int )xPortNumber ) );
+
+ if( xSocket != FREERTOS_NO_SOCKET )
+ {
+ xAddress.sin_addr = FreeRTOS_GetIPAddress(); // Single NIC, currently not used
+ xAddress.sin_port = FreeRTOS_htons( xPortNumber );
+
+ FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );
+ FreeRTOS_listen( xSocket, pxConfigs[ xIndex ].xBackLog );
+
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) );
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) );
+
+ #if( ipconfigHTTP_RX_BUFSIZE > 0 )
+ {
+ if( pxConfigs[ xIndex ].eType == eSERVER_HTTP )
+ {
+ WinProperties_t xWinProps;
+
+ memset( &xWinProps, '\0', sizeof( xWinProps ) );
+ /* The parent socket itself won't get connected. The properties below
+ will be inherited by each new child socket. */
+ xWinProps.lTxBufSize = ipconfigHTTP_TX_BUFSIZE;
+ xWinProps.lTxWinSize = ipconfigHTTP_TX_WINSIZE;
+ xWinProps.lRxBufSize = ipconfigHTTP_RX_BUFSIZE;
+ xWinProps.lRxWinSize = ipconfigHTTP_RX_WINSIZE;
+
+ /* Set the window and buffer sizes. */
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) );
+ }
+ }
+ #endif
+
+ FreeRTOS_FD_SET( xSocket, xSocketSet, eSELECT_READ|eSELECT_EXCEPT );
+ pxServer->xServers[ xIndex ].xSocket = xSocket;
+ pxServer->xServers[ xIndex ].eType = pxConfigs[ xIndex ].eType;
+ pxServer->xServers[ xIndex ].pcRootDir = strnew( pxConfigs[ xIndex ].pcRootDir );
+ prvRemoveSlash( ( char * ) pxServer->xServers[ xIndex ].pcRootDir );
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Could not allocate the server, delete the socket set */
+ FreeRTOS_DeleteSocketSet( xSocketSet );
+ }
+ }
+ else
+ {
+ /* Could not create a socket set, return NULL */
+ pxServer = NULL;
+ }
+
+ return pxServer;
+}
+/*-----------------------------------------------------------*/
+
+static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket )
+{
+TCPClient_t *pxClient = NULL;
+BaseType_t xSize = 0;
+FTCPWorkFunction fWorkFunc = NULL;
+FTCPDeleteFunction fDeleteFunc = NULL;
+const char *pcType = "Unknown";
+
+ /*_RB_ Can the work and delete functions be part of the xSERVER_CONFIG structure
+ becomes generic, with no pre-processing required? */
+ #if( ipconfigUSE_HTTP != 0 )
+ {
+ if( pxServer->xServers[ xIndex ].eType == eSERVER_HTTP )
+ {
+ xSize = sizeof( HTTPClient_t );
+ fWorkFunc = xHTTPClientWork;
+ fDeleteFunc = vHTTPClientDelete;
+ pcType = "HTTP";
+ }
+ }
+ #endif /* ipconfigUSE_HTTP != 0 */
+
+ #if( ipconfigUSE_FTP != 0 )
+ {
+ if( pxServer->xServers[ xIndex ].eType == eSERVER_FTP )
+ {
+ xSize = sizeof( FTPClient_t );
+ fWorkFunc = xFTPClientWork;
+ fDeleteFunc = vFTPClientDelete;
+ pcType = "FTP";
+ }
+ }
+ #endif /* ipconfigUSE_FTP != 0 */
+
+ /* Malloc enough space for a new HTTP-client */
+ if( xSize )
+ {
+ pxClient = ( TCPClient_t* ) pvPortMallocLarge( xSize );
+ }
+
+ if( pxClient != NULL )
+ {
+ memset( pxClient, '\0', xSize );
+
+ /* Put the new client in front of the list. */
+ pxClient->eType = pxServer->xServers[ xIndex ].eType;
+ pxClient->pcRootDir = pxServer->xServers[ xIndex ].pcRootDir;
+ pxClient->pxParent = pxServer;
+ pxClient->xSocket = xNexSocket;
+ pxClient->pxNextClient = pxServer->pxClients;
+ pxClient->fWorkFunction = fWorkFunc;
+ pxClient->fDeleteFunction = fDeleteFunc;
+ pxServer->pxClients = pxClient;
+
+ FreeRTOS_FD_SET( xNexSocket, pxServer->xSocketSet, eSELECT_READ|eSELECT_EXCEPT );
+ }
+ else
+ {
+ pcType = "closed";
+ FreeRTOS_closesocket( xNexSocket );
+ }
+
+ FreeRTOS_printf( ( "TPC-server: new %s client\n", pcType ) );
+
+ /* Remove compiler warnings in case FreeRTOS_printf() is not used. */
+ ( void ) pcType;
+}
+/*-----------------------------------------------------------*/
+
+void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime )
+{
+TCPClient_t **ppxClient;
+BaseType_t xIndex;
+BaseType_t xRc;
+
+ /* Let the server do one working cycle */
+ xRc = FreeRTOS_select( pxServer->xSocketSet, xBlockingTime );
+
+ if( xRc != 0 )
+ {
+ for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )
+ {
+ struct freertos_sockaddr xAddress;
+ Socket_t xNexSocket;
+ socklen_t xSocketLength;
+
+ if( pxServer->xServers[ xIndex ].xSocket == FREERTOS_NO_SOCKET )
+ {
+ continue;
+ }
+
+ xSocketLength = sizeof( xAddress );
+ xNexSocket = FreeRTOS_accept( pxServer->xServers[ xIndex ].xSocket, &xAddress, &xSocketLength);
+
+ if( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) )
+ {
+ prvReceiveNewClient( pxServer, xIndex, xNexSocket );
+ }
+ }
+ }
+
+ ppxClient = &pxServer->pxClients;
+
+ while( ( * ppxClient ) != NULL )
+ {
+ TCPClient_t *pxThis = *ppxClient;
+
+ /* Almost C++ */
+ xRc = pxThis->fWorkFunction( pxThis );
+
+ if (xRc < 0 )
+ {
+ *ppxClient = pxThis->pxNextClient;
+ /* Close handles, resources */
+ pxThis->fDeleteFunction( pxThis );
+ /* Free the space */
+ vPortFreeLarge( pxThis );
+ }
+ else
+ {
+ ppxClient = &( pxThis->pxNextClient );
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static char *strnew( const char *pcString )
+{
+BaseType_t xLength;
+char *pxBuffer;
+
+ xLength = strlen( pcString ) + 1;
+ pxBuffer = ( char * ) pvPortMalloc( xLength );
+ if( pxBuffer != NULL )
+ {
+ memcpy( pxBuffer, pcString, xLength );
+ }
+
+ return pxBuffer;
+}
+/*-----------------------------------------------------------*/
+
+static void prvRemoveSlash( char *pcDir )
+{
+BaseType_t xLength = strlen( pcDir );
+
+ while( ( xLength > 0 ) && ( pcDir[ xLength - 1 ] == '/' ) )
+ {
+ pcDir[ --xLength ] = '\0';
+ }
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigSUPPORT_SIGNALS != 0 )
+
+ /* FreeRTOS_TCPServerWork() calls select().
+ The two functions below provide a possibility to interrupt
+ the call to select(). After the interruption, resume
+ by calling FreeRTOS_TCPServerWork() again. */
+ BaseType_t FreeRTOS_TCPServerSignal( TCPServer_t *pxServer )
+ {
+ BaseType_t xIndex;
+ BaseType_t xResult = pdFALSE;
+ for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )
+ {
+ if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )
+ {
+ FreeRTOS_SignalSocket( pxServer->xServers[ xIndex ].xSocket );
+ xResult = pdTRUE;
+ break;
+ }
+ }
+
+ return xResult;
+ }
+
+#endif /* ipconfigSUPPORT_SIGNALS */
+/*-----------------------------------------------------------*/
+
+#if( ipconfigSUPPORT_SIGNALS != 0 )
+
+ /* Same as above: this function may be called from an ISR,
+ for instance a GPIO interrupt. */
+ BaseType_t FreeRTOS_TCPServerSignalFromISR( TCPServer_t *pxServer, BaseType_t *pxHigherPriorityTaskWoken )
+ {
+ BaseType_t xIndex;
+ BaseType_t xResult = pdFALSE;
+ for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )
+ {
+ if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )
+ {
+ FreeRTOS_SignalSocketFromISR( pxServer->xServers[ xIndex ].xSocket, pxHigherPriorityTaskWoken );
+ xResult = pdTRUE;
+ break;
+ }
+ }
+
+ return xResult;
+ }
+#endif /* ipconfigSUPPORT_SIGNALS */
+/*-----------------------------------------------------------*/
+
+#endif /* ipconfigUSE_TCP != 1 */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_commands.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_commands.c
new file mode 100644
index 000000000..7e49e8305
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_commands.c
@@ -0,0 +1,106 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_FTP_commands.h"
+
+const FTPCommand_t xFTPCommands[ FTP_CMD_COUNT ] =
+{
+/* cmdLen cmdName[7] cmdType checkLogin checkNullArg */
+ { 4, "USER", ECMD_USER, pdFALSE, pdFALSE },
+ { 4, "PASS", ECMD_PASS, pdFALSE, pdFALSE },
+ { 4, "ACCT", ECMD_ACCT, pdTRUE, pdFALSE },
+ { 3, "CWD", ECMD_CWD, pdTRUE, pdTRUE },
+ { 4, "CDUP", ECMD_CDUP, pdTRUE, pdFALSE },
+ { 4, "SMNT", ECMD_SMNT, pdTRUE, pdFALSE },
+ { 4, "QUIT", ECMD_QUIT, pdTRUE, pdFALSE },
+ { 4, "REIN", ECMD_REIN, pdTRUE, pdFALSE },
+ { 4, "PORT", ECMD_PORT, pdTRUE, pdFALSE },
+ { 4, "PASV", ECMD_PASV, pdTRUE, pdFALSE },
+ { 4, "TYPE", ECMD_TYPE, pdTRUE, pdFALSE },
+ { 4, "STRU", ECMD_STRU, pdTRUE, pdFALSE },
+ { 4, "MODE", ECMD_MODE, pdTRUE, pdFALSE },
+ { 4, "RETR", ECMD_RETR, pdTRUE, pdTRUE },
+ { 4, "STOR", ECMD_STOR, pdTRUE, pdTRUE },
+ { 4, "STOU", ECMD_STOU, pdTRUE, pdFALSE },
+ { 4, "APPE", ECMD_APPE, pdTRUE, pdFALSE },
+ { 4, "ALLO", ECMD_ALLO, pdTRUE, pdFALSE },
+ { 4, "REST", ECMD_REST, pdTRUE, pdFALSE },
+ { 4, "RNFR", ECMD_RNFR, pdTRUE, pdTRUE },
+ { 4, "RNTO", ECMD_RNTO, pdTRUE, pdTRUE },
+ { 4, "ABOR", ECMD_ABOR, pdTRUE, pdFALSE },
+ { 4, "SIZE", ECMD_SIZE, pdTRUE, pdTRUE },
+ { 4, "MDTM", ECMD_MDTM, pdTRUE, pdTRUE },
+ { 4, "DELE", ECMD_DELE, pdTRUE, pdTRUE },
+ { 3, "RMD", ECMD_RMD, pdTRUE, pdTRUE },
+ { 3, "MKD", ECMD_MKD, pdTRUE, pdTRUE },
+ { 3, "PWD", ECMD_PWD, pdTRUE, pdFALSE },
+ { 4, "LIST", ECMD_LIST, pdTRUE, pdFALSE },
+ { 4, "NLST", ECMD_NLST, pdTRUE, pdFALSE },
+ { 4, "SITE", ECMD_SITE, pdTRUE, pdFALSE },
+ { 4, "SYST", ECMD_SYST, pdFALSE, pdFALSE },
+ { 4, "FEAT", ECMD_FEAT, pdFALSE, pdFALSE },
+ { 4, "STAT", ECMD_STAT, pdTRUE, pdFALSE },
+ { 4, "HELP", ECMD_HELP, pdFALSE, pdFALSE },
+ { 4, "NOOP", ECMD_NOOP, pdFALSE, pdFALSE },
+ { 4, "EMPT", ECMD_EMPTY, pdFALSE, pdFALSE },
+ { 4, "CLOS", ECMD_CLOSE, pdTRUE, pdFALSE },
+ { 4, "UNKN", ECMD_UNKNOWN, pdFALSE, pdFALSE },
+};
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_server.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_server.c
new file mode 100644
index 000000000..2e75a6355
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_server.c
@@ -0,0 +1,2669 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "portmacro.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_TCP_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_Stream_Buffer.h"
+
+/* FreeRTOS Protocol includes. */
+#include "FreeRTOS_FTP_commands.h"
+#include "FreeRTOS_TCP_server.h"
+#include "FreeRTOS_server_private.h"
+
+/* Remove the whole file if FTP is not supported. */
+#if( ipconfigUSE_FTP == 1 )
+
+#ifndef HTTP_SERVER_BACKLOG
+ #define HTTP_SERVER_BACKLOG ( 12 )
+#endif
+
+#if !defined( ARRAY_SIZE )
+ #define ARRAY_SIZE( x ) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] )
+#endif
+
+#if defined(__WIN32__) && !defined(ipconfigFTP_FS_USES_BACKSLAH)
+ #define ipconfigFTP_FS_USES_BACKSLAH 1
+#endif
+
+/* Some defines to make the code more readbale */
+#define pcCOMMAND_BUFFER pxClient->pxParent->pcCommandBuffer
+#define pcNEW_DIR pxClient->pxParent->pcNewDir
+#define pcFILE_BUFFER pxClient->pxParent->pcFileBuffer
+
+/* This FTP server will only do binary transfers */
+#define TMODE_BINARY 1
+#define TMODE_ASCII 2
+#define TMODE_7BITS 3
+#define TMODE_8BITS 4
+
+/* Ascii character definitions. */
+#define ftpASCII_CR 13
+#define ftpASCII_LF 10
+
+#if defined( FTP_WRITES_ALIGNED ) || defined( ipconfigFTP_WRITES_ALIGNED )
+ #error Name change : please rename the define to the new name 'ipconfigFTP_ZERO_COPY_ALIGNED_WRITES'
+#endif
+
+/*
+ * ipconfigFTP_ZERO_COPY_ALIGNED_WRITES : experimental optimisation option.
+ * If non-zero, receiving data will be done with the zero-copy method and also
+ * writes to disk will be done with sector-alignment as much as possible.
+ */
+#ifndef ipconfigFTP_ZERO_COPY_ALIGNED_WRITES
+ #define ipconfigFTP_ZERO_COPY_ALIGNED_WRITES 0
+#endif
+
+/*
+ * This module only has 2 public functions:
+ */
+BaseType_t xFTPClientWork( TCPClient_t *pxClient );
+void vFTPClientDelete( TCPClient_t *pxClient );
+
+/*
+ * Process a single command.
+ */
+static BaseType_t prvProcessCommand( FTPClient_t *pxClient, BaseType_t xIndex, char *pcRestCommand );
+
+/*
+ * Create a socket for a data connection to the FTP client.
+ */
+static BaseType_t prvTransferConnect( FTPClient_t *pxClient, BaseType_t xDoListen );
+
+/*
+ * Either call listen() or connect() to start the transfer connection.
+ */
+static BaseType_t prvTransferStart( FTPClient_t *pxClient );
+
+/*
+ * See if the socket has got connected or disconnected. Close the socket if
+ * necessary.
+ */
+static void prvTransferCheck( FTPClient_t *pxClient );
+
+/*
+ * Close the data socket and issue some informative logging.
+ */
+static void prvTransferCloseSocket( FTPClient_t *pxClient );
+
+/*
+ * Close the file handle (pxReadHandle or pxWriteHandle).
+ */
+static void prvTransferCloseFile( FTPClient_t *pxClient );
+
+/*
+ * Close a directory (-handle).
+ */
+static void prvTransferCloseDir( FTPClient_t *pxClient );
+
+/*
+ * Translate a string (indicating a transfer type) to a number.
+ */
+static BaseType_t prvGetTransferType( const char *pcType );
+
+#if( ipconfigHAS_PRINTF != 0 )
+ /*
+ * For nice logging: write an amount (number of bytes), e.g. 3512200 as
+ * "3.45 MB"
+ */
+ static const char *pcMkSize( uint32_t ulAmount, char *pcBuffer, BaseType_t xBufferSize );
+#endif
+
+#if( ipconfigHAS_PRINTF != 0 )
+ /*
+ * Calculate the average as bytes-per-second, when amount and milliseconds
+ * are known.
+ */
+ static uint32_t ulGetAverage( uint32_t ulAmount, TickType_t xDeltaMs );
+#endif
+
+/*
+ * A port command looks like: PORT h1,h2,h3,h4,p1,p2. Parse it and translate it
+ * to an IP-address and a port number.
+ */
+static UBaseType_t prvParsePortData( const char *pcCommand, uint32_t *pulIPAddress );
+
+/*
+ * CWD: Change current working directory.
+ */
+
+static BaseType_t prvChangeDir( FTPClient_t *pxClient, char *pcDirectory );
+
+/*
+ * RNFR: Rename from ...
+ */
+static BaseType_t prvRenameFrom( FTPClient_t *pxClient, const char *pcFileName );
+
+/*
+ * RNTO: Rename to ...
+ */
+static BaseType_t prvRenameTo( FTPClient_t *pxClient, const char *pcFileName );
+
+/*
+ * SITE: Change file permissions.
+ */
+static BaseType_t prvSiteCmd( FTPClient_t *pxClient, char *pcRestCommand );
+
+/*
+ * DELE: Delete a file.
+ */
+static BaseType_t prvDeleteFile( FTPClient_t *pxClient, char *pcFileName );
+
+/*
+ * SIZE: get the size of a file (xSendDate = 0).
+ * MDTM: get data and time properties (xSendDate = 1).
+ */
+static BaseType_t prvSizeDateFile( FTPClient_t *pxClient, char *pcFileName, BaseType_t xSendDate );
+
+/*
+ * MKD: Make / create a directory (xDoRemove = 0).
+ * RMD: Remove a directory (xDoRemove = 1).
+ */
+static BaseType_t prvMakeRemoveDir( FTPClient_t *pxClient, const char *pcDirectory, BaseType_t xDoRemove );
+
+/*
+ * The next three commands: LIST, RETR and STOR all require a data socket.
+ * The data connection is either started with a 'PORT' or a 'PASV' command.
+ * Each of the commands has a prepare- (Prep) and a working- (Work) function.
+ * The Work function should be called as long as the data socket is open, and
+ * there is data to be transmitted.
+ */
+
+/*
+ * LIST: Send a directory listing in Unix style.
+ */
+static BaseType_t prvListSendPrep( FTPClient_t *pxClient );
+static BaseType_t prvListSendWork( FTPClient_t *pxClient );
+
+/*
+ * RETR: Send a file to the FTP client.
+ */
+static BaseType_t prvRetrieveFilePrep( FTPClient_t *pxClient, char *pcFileName );
+static BaseType_t prvRetrieveFileWork( FTPClient_t *pxClient );
+
+/*
+ * STOR: Receive a file from the FTP client and store it.
+ */
+static BaseType_t prvStoreFilePrep( FTPClient_t *pxClient, char *pcFileName );
+static BaseType_t prvStoreFileWork( FTPClient_t *pxClient );
+
+/*
+ * Print/format a single directory entry in Unix style.
+ */
+static BaseType_t prvGetFileInfoStat( FF_DirEnt_t *pxEntry, char *pcLine, BaseType_t xMaxLength );
+
+/*
+ * Send a reply to a socket, either the command- or the data-socket.
+ */
+static BaseType_t prvSendReply( Socket_t xSocket, const char *pcBuffer, BaseType_t xLength );
+
+/*
+ * Prepend the root directory (if any), plus the current working directory
+ * (always), to get an absolute path.
+ */
+BaseType_t xMakeAbsolute( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcPath );
+
+/*
+
+####### ##### ###### # # ##
+ # ## # # # # # # # #
+ # # # # # # #
+ # # # # # # # #### ### ## # #
+ ##### # ##### # # # # # # # # # #
+ # # # # # # # # # ## # ####
+ # # # ## ## # # # # #
+ # # # ## ## # # # # #
+#### #### #### ## ## #### #### ## ##
+
+ * xFTPClientWork()
+ * will be called by FreeRTOS_TCPServerWork(), after select has expired().
+ * FD_ISSET will not be used. This work function will always be called at
+ * regular intervals, and also after a select() event has occurred.
+ */
+BaseType_t xFTPClientWork( TCPClient_t *pxTCPClient )
+{
+FTPClient_t *pxClient = ( FTPClient_t * ) pxTCPClient;
+BaseType_t xRc;
+
+ if( pxClient->bits.bHelloSent == pdFALSE_UNSIGNED )
+ {
+ BaseType_t xLength;
+
+ pxClient->bits.bHelloSent = pdTRUE_UNSIGNED;
+
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "220 Welcome to the FreeRTOS+TCP FTP server\r\n" );
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+ }
+
+ /* Call recv() in a non-blocking way, to see if there is an FTP command
+ sent to this server. */
+ xRc = FreeRTOS_recv( pxClient->xSocket, ( void * )pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), 0 );
+
+ if( xRc > 0 )
+ {
+ BaseType_t xIndex;
+ const FTPCommand_t *pxCommand;
+ char *pcRestCommand;
+
+ if( xRc < ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) )
+ {
+ pcCOMMAND_BUFFER[ xRc ] = '\0';
+ }
+
+ while( xRc && ( ( pcCOMMAND_BUFFER[ xRc - 1 ] == ftpASCII_CR ) || ( pcCOMMAND_BUFFER[ xRc - 1 ] == ftpASCII_LF ) ) )
+ {
+ pcCOMMAND_BUFFER[ --xRc ] = '\0';
+ }
+
+ /* Now iterate through a list of FTP commands, and look for a match. */
+ pxCommand = xFTPCommands;
+ pcRestCommand = pcCOMMAND_BUFFER;
+ for( xIndex = 0; xIndex < FTP_CMD_COUNT - 1; xIndex++, pxCommand++ )
+ {
+ BaseType_t xLength;
+
+ /* The length of each command is stored as well, just to be a bit
+ quicker here. */
+ xLength = pxCommand->xCommandLength;
+
+ if( ( xRc >= xLength ) && ( memcmp( ( const void * ) pxCommand->pcCommandName, ( const void * ) pcCOMMAND_BUFFER, xLength ) == 0 ) )
+ {
+ /* A match with an existing command is found. Skip any
+ whitespace to get the first parameter. */
+ pcRestCommand += xLength;
+ while( ( *pcRestCommand == ' ' ) || ( *pcRestCommand == '\t' ) )
+ {
+ pcRestCommand++;
+ }
+ break;
+ }
+ }
+
+ /* If the command received was not recognised, xIndex will point to a
+ fake entry called 'ECMD_UNKNOWN'. */
+ prvProcessCommand( pxClient, xIndex, pcRestCommand );
+ }
+ else if( xRc < 0 )
+ {
+ /* The connection will be closed and the client will be deleted. */
+ FreeRTOS_printf( ( "xFTPClientWork: xRc = %ld\n", xRc ) );
+ }
+
+ /* Does it have an open data connection? */
+ if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET )
+ {
+ /* See if the connection has changed. */
+ prvTransferCheck( pxClient );
+
+ /* "pcConnectionAck" contains a string like:
+ "Response: 150 Accepted data connection from 192.168.2.3:6789"
+ The socket can only be used once this acknowledgement has been sent. */
+ if( ( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) && ( pxClient->pcConnectionAck[ 0 ] == '\0' ) )
+ {
+ BaseType_t xClientRc = 0;
+
+ if( pxClient->bits1.bDirHasEntry )
+ {
+ /* Still listing a directory. */
+ xClientRc = prvListSendWork( pxClient );
+ }
+ else if( pxClient->pxReadHandle != NULL )
+ {
+ /* Sending a file. */
+ xClientRc = prvRetrieveFileWork( pxClient );
+ }
+ else if( pxClient->pxWriteHandle != NULL )
+ {
+ /* Receiving a file. */
+ xClientRc = prvStoreFileWork( pxClient );
+ }
+
+ if( xClientRc < 0 )
+ {
+ prvTransferCloseSocket( pxClient );
+ prvTransferCloseFile( pxClient );
+ }
+ }
+ }
+
+ return xRc;
+}
+/*-----------------------------------------------------------*/
+
+static void prvTransferCloseDir( FTPClient_t *pxClient )
+{
+ /* Nothing to close for +FAT. */
+ ( void ) pxClient;
+}
+/*-----------------------------------------------------------*/
+
+void vFTPClientDelete( TCPClient_t *pxTCPClient )
+{
+FTPClient_t *pxClient = ( FTPClient_t * ) pxTCPClient;
+
+ /* Close any directory-listing-handles (not used by +FAT ). */
+ prvTransferCloseDir( pxClient );
+ /* Close the data-socket. */
+ prvTransferCloseSocket( pxClient );
+ /* Close any open file handle. */
+ prvTransferCloseFile( pxClient );
+
+ /* Close the FTP command socket */
+ if( pxClient->xSocket != FREERTOS_NO_SOCKET )
+ {
+ FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL );
+ FreeRTOS_closesocket( pxClient->xSocket );
+ pxClient->xSocket = FREERTOS_NO_SOCKET;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvProcessCommand( FTPClient_t *pxClient, BaseType_t xIndex, char *pcRestCommand )
+{
+const FTPCommand_t *pxFTPCommand = &( xFTPCommands[ xIndex ] );
+const char *pcMyReply = NULL;
+BaseType_t xResult = 0;
+
+ if( ( pxFTPCommand->ucCommandType != ECMD_PASS ) && ( pxFTPCommand->ucCommandType != ECMD_PORT ) )
+ {
+ FreeRTOS_printf( ( " %s %s\n", pxFTPCommand->pcCommandName, pcRestCommand ) );
+ }
+
+ if( ( pxFTPCommand->checkLogin != pdFALSE ) && ( pxClient->bits.bLoggedIn == pdFALSE_UNSIGNED ) )
+ {
+ pcMyReply = REPL_530; /* Please first log in. */
+ }
+ else if( ( pxFTPCommand->checkNullArg != pdFALSE ) && ( ( pcRestCommand == NULL ) || ( pcRestCommand[ 0 ] == '\0' ) ) )
+ {
+ pcMyReply = REPL_501; /* Command needs a parameter. */
+ }
+
+ if( pcMyReply == NULL )
+ {
+ switch( pxFTPCommand->ucCommandType )
+ {
+ case ECMD_USER: /* User. */
+ /* User name has been entered, expect password. */
+ pxClient->bits.bStatusUser = pdTRUE_UNSIGNED;
+
+ #if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 )/*_RB_ Needs defaulting and adding to the web documentation. */
+ {
+ /* Save the user name in 'pcFileName'. */
+ snprintf( pxClient->pcFileName, sizeof( pxClient->pcFileName ), "%s", pcRestCommand );
+
+ /* The USER name is presented to the application. The function
+ may return a const string like "331 Please enter your
+ password\r\n". */
+ pcMyReply = pcApplicationFTPUserHook( pxClient->pcFileName );
+ if( pcMyReply == NULL )
+ {
+ pcMyReply = REPL_331_ANON;
+ }
+ }
+ #else
+ {
+ /* No password checks, any password will be accepted. */
+ pcMyReply = REPL_331_ANON;
+ }
+ #endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 */
+
+ #if( ipconfigFTP_HAS_USER_PROPERTIES_HOOK != 0 )/*_RB_ Needs defaulting and adding to the web documentation. */
+ {
+ FTPUserProperties_t xProperties;
+
+ xProperties.pcRootDir = pxClient->pcRootDir;
+ xProperties.xReadOnly = pdFALSE;
+ xProperties.usPortNumber = pxClient->usClientPort;
+ vApplicationFTPUserPropertiesHook( pxClient->pcFileName, &( xProperties ) );
+
+ if( xProperties.pcRootDir != NULL )
+ {
+ pxClient->pcRootDir = xProperties.pcRootDir;
+ }
+ pxClient->bits.bReadOnly = ( xProperties.xReadOnly != pdFALSE_UNSIGNED );
+ }
+ #endif /* ipconfigFTP_HAS_USER_PROPERTIES_HOOK */
+ break;
+
+ case ECMD_PASS: /* Password. */
+ pxClient->ulRestartOffset = 0;
+ if( pxClient->bits.bStatusUser == pdFALSE_UNSIGNED )
+ {
+ pcMyReply = REPL_503; /* "503 Bad sequence of commands.\r\n". */
+ }
+ else
+ {
+ BaseType_t xAllow;
+
+ pxClient->bits.bStatusUser = pdFALSE_UNSIGNED;
+ #if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 )
+ {
+ xAllow = xApplicationFTPPasswordHook( pxClient->pcFileName, pcRestCommand );
+ }
+ #else
+ {
+ xAllow = 1;
+ }
+ #endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */
+
+ if( xAllow > 0 )
+ {
+ pxClient->bits.bLoggedIn = pdTRUE_UNSIGNED; /* Client has now logged in. */
+ pcMyReply = "230 OK. Current directory is /\r\n";
+ }
+ else
+ {
+ pcMyReply = "530 Login incorrect\r\n"; /* 530 Login incorrect. */
+ }
+
+ strcpy( pxClient->pcCurrentDir, ( const char * ) "/" );
+ }
+ break;
+
+ case ECMD_SYST: /* System. */
+ snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "215 UNIX Type: L8\r\n" );
+ pcMyReply = pcCOMMAND_BUFFER;
+ break;
+
+ case ECMD_PWD: /* Get working directory. */
+ xMakeRelative( pxClient, pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), pxClient->pcCurrentDir );
+ snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), REPL_257_PWD, pcFILE_BUFFER );
+ pcMyReply = pcCOMMAND_BUFFER;
+ break;
+
+ case ECMD_REST:
+ if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED )
+ {
+ pcMyReply = REPL_553_READ_ONLY;
+ }
+ else
+ {
+ const char *pcPtr = pcRestCommand;
+
+ while( *pcPtr == ' ' )
+ {
+ pcPtr++;
+ }
+
+ if( ( *pcPtr >= '0' ) && ( *pcPtr <= '9' ) )
+ {
+ sscanf( pcPtr, "%lu", &pxClient->ulRestartOffset );
+ snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "350 Restarting at %lu. Send STORE or RETRIEVE\r\n", pxClient->ulRestartOffset );
+ pcMyReply = pcCOMMAND_BUFFER;
+ }
+ else
+ {
+ pcMyReply = REPL_500; /* 500 Syntax error, command unrecognised. */
+ }
+ }
+ break;
+
+ case ECMD_NOOP: /* NOP operation */
+ if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET )
+ {
+ pcMyReply = REPL_200_PROGRESS;
+ }
+ else
+ {
+ pcMyReply = REPL_200;
+ }
+ break;
+
+ case ECMD_TYPE: /* Ask or set transfer type. */
+ {
+ /* e.g. "TYPE I" for Images (binary). */
+ BaseType_t xType = prvGetTransferType( pcRestCommand );
+
+ if( xType < 0 )
+ {
+ /* TYPE not recognised. */
+ pcMyReply = REPL_500;
+ }
+ else
+ {
+ pxClient->xTransType = xType;
+ pcMyReply = REPL_200;
+ }
+ }
+ break;
+
+ case ECMD_PASV: /* Enter passive mode. */
+ /* Connect passive: Server will listen() and wait for a connection.
+ Start up a new data connection with 'xDoListen' set to true. */
+ if( prvTransferConnect( pxClient, pdTRUE ) == pdFALSE )
+ {
+ pcMyReply = REPL_502;
+ }
+ else
+ {
+ uint32_t ulIP;
+ uint16_t ulPort;
+ struct freertos_sockaddr xLocalAddress;
+ struct freertos_sockaddr xRemoteAddress;
+
+ FreeRTOS_GetLocalAddress( pxClient->xTransferSocket, &xLocalAddress );
+ FreeRTOS_GetRemoteAddress( pxClient->xSocket, &xRemoteAddress );
+
+ ulIP = FreeRTOS_ntohl( xLocalAddress.sin_addr );
+ pxClient->ulClientIP = FreeRTOS_ntohl( xRemoteAddress.sin_addr );
+ ulPort = FreeRTOS_ntohs( xLocalAddress.sin_port );
+
+ pxClient->usClientPort = FreeRTOS_ntohs( xRemoteAddress.sin_port );
+
+ /* REPL_227_D "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d). */
+ snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), REPL_227_D,
+ ( unsigned )ulIP >> 24,
+ ( unsigned )( ulIP >> 16 ) & 0xFF,
+ ( unsigned )( ulIP >> 8 ) & 0xFF,
+ ( unsigned )ulIP & 0xFF,
+ ( unsigned )ulPort >> 8,
+ ( unsigned )ulPort & 0xFF );
+
+ pcMyReply = pcCOMMAND_BUFFER;
+ }
+ break;
+
+ case ECMD_PORT: /* Active connection to the client. */
+ /* The client uses this command to tell the server to what
+ client-side port the server should contact; use of this command
+ indicates an active data transfer. e.g. PORT 192,168,1,2,4,19. */
+ {
+ uint32_t ulIPAddress = 0;
+ UBaseType_t uxPort;
+
+ uxPort = prvParsePortData( pcRestCommand, &ulIPAddress );
+ FreeRTOS_printf( (" PORT %lxip:%ld\n", ulIPAddress, uxPort ) );
+
+ if( uxPort == 0u )
+ {
+ pcMyReply = REPL_501;
+ }
+ else if( prvTransferConnect( pxClient, pdFALSE ) == pdFALSE )
+ {
+ /* Call prvTransferConnect() with 'xDoListen' = false for an
+ active connect(). */
+ pcMyReply = REPL_501;
+ }
+ else
+ {
+ pxClient->usClientPort = ( uint16_t ) uxPort;
+ pxClient->ulClientIP = ulIPAddress;
+ FreeRTOS_printf( ("Client address %lxip:%lu\n", ulIPAddress, uxPort ) );
+ pcMyReply = REPL_200;
+ }
+ }
+ break;
+
+ case ECMD_CWD: /* Change current working directory. */
+ prvChangeDir( pxClient, pcRestCommand );
+ break;
+
+ case ECMD_RNFR:
+ if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED )
+ {
+ pcMyReply = REPL_553_READ_ONLY;
+ }
+ else
+ {
+ prvRenameFrom( pxClient, pcRestCommand );
+ }
+ break;
+
+ case ECMD_RNTO:
+ if( pxClient->bits.bInRename == pdFALSE_UNSIGNED )
+ {
+ pcMyReply = REPL_503; /* "503 Bad sequence of commands. */
+ }
+ else
+ {
+ prvRenameTo( pxClient, pcRestCommand );
+ }
+ break;
+
+ case ECMD_SITE: /* Set file permissions */
+ if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED )
+ {
+ pcMyReply = REPL_553_READ_ONLY;
+ }
+ else if( prvSiteCmd( pxClient, pcRestCommand ) == pdFALSE )
+ {
+ pcMyReply = REPL_202;
+ }
+ break;
+
+ case ECMD_DELE:
+ if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED )
+ {
+ pcMyReply = REPL_553_READ_ONLY;
+ }
+ else
+ {
+ prvDeleteFile( pxClient, pcRestCommand );
+ }
+ break;
+
+ case ECMD_MDTM:
+ prvSizeDateFile( pxClient, pcRestCommand, pdTRUE );
+ break;
+
+ case ECMD_SIZE:
+ if( pxClient->pxWriteHandle != NULL )
+ {
+ /* This SIZE query is probably about a file which is now being
+ received. If so, return the value of pxClient->ulRecvBytes,
+ pcRestCommand points to 'pcCommandBuffer', make it free by
+ copying it to pcNewDir. */
+
+ xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcRestCommand );
+
+ if( strcmp( pcNEW_DIR, pcRestCommand ) == 0 )
+ {
+ BaseType_t xCount;
+ for( xCount = 0; xCount < 3 && pxClient->pxWriteHandle; xCount++ )
+ {
+ prvStoreFileWork( pxClient );
+ }
+ if( pxClient->pxWriteHandle != NULL )
+ {
+ /* File being queried is still open, return number of
+ bytes received until now. */
+ snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %lu\r\n", pxClient->ulRecvBytes );
+ pcMyReply = pcCOMMAND_BUFFER;
+ } /* otherwise, do a normal stat(). */
+ }
+ strcpy( pcRestCommand, pcNEW_DIR );
+ }
+ if( pcMyReply == NULL )
+ {
+ prvSizeDateFile( pxClient, pcRestCommand, pdFALSE );
+ }
+ break;
+ case ECMD_MKD:
+ case ECMD_RMD:
+ if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED )
+ {
+ pcMyReply = REPL_553_READ_ONLY;
+ }
+ else
+ {
+ prvMakeRemoveDir( pxClient, pcRestCommand, pxFTPCommand->ucCommandType == ECMD_RMD );
+ }
+ break;
+ case ECMD_CDUP:
+ prvChangeDir( pxClient, ".." );
+ break;
+
+ case ECMD_QUIT:
+ prvSendReply( pxClient->xSocket, REPL_221, 0 );
+ pxClient->bits.bLoggedIn = pdFALSE_UNSIGNED;
+ break;
+ case ECMD_LIST:
+ case ECMD_RETR:
+ case ECMD_STOR:
+ if( ( pxClient->xTransferSocket == FREERTOS_NO_SOCKET ) &&
+ ( ( pxFTPCommand->ucCommandType != ECMD_STOR ) ||
+ ( pxClient->bits1.bEmptyFile == pdFALSE_UNSIGNED ) ) )
+ {
+ /* Sending "425 Can't open data connection." :
+ Before receiving any of these commands, there must have been a
+ PORT or PASV command, which causes the creation of a data socket. */
+ /* There is one exception: a STOR command is received while the
+ data connection has already been closed. This is tested with the
+ 'bEmptyFile' flag. */
+ pcMyReply = REPL_425;
+ }
+ else
+ {
+ /* In case an empty file was received ( bits1.bEmptyFile ), the
+ transfer socket never delivered any data. Check if the transfer
+ socket is still open: */
+ if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET )
+ {
+ prvTransferCheck( pxClient );
+ }
+ switch( pxFTPCommand->ucCommandType )
+ {
+ case ECMD_LIST:
+ prvListSendPrep( pxClient );
+ break;
+ case ECMD_RETR:
+ prvRetrieveFilePrep( pxClient, pcRestCommand );
+ break;
+ case ECMD_STOR:
+ if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED )
+ {
+ pcMyReply = REPL_553_READ_ONLY;
+ }
+ else
+ {
+ prvStoreFilePrep( pxClient, pcRestCommand );
+ if( pxClient->bits1.bEmptyFile != pdFALSE_UNSIGNED )
+ {
+ /* Although the 'xTransferSocket' is closed already,
+ call this function just for the logging. */
+ prvTransferCloseSocket( pxClient );
+
+ /* Close an empty file. */
+ prvTransferCloseFile( pxClient );
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case ECMD_FEAT:
+ {
+ static const char pcFeatAnswer[] =
+ "211-Features:\x0a"
+ /* The MDTM command is only allowed when
+ there is support for date&time. */
+ #if( ffconfigTIME_SUPPORT != 0 )
+ " MDTM\x0a"
+ #endif
+ " REST STREAM\x0a"
+ " SIZE\x0d\x0a"
+ "211 End\x0d\x0a";
+ pcMyReply = pcFeatAnswer;
+ }
+ break;
+
+ case ECMD_UNKNOWN:
+ FreeRTOS_printf( ("ftp::processCmd: Cmd %s unknown\n", pcRestCommand ) );
+ pcMyReply = REPL_500;
+ break;
+ }
+ }
+ if( pxFTPCommand->ucCommandType != ECMD_RNFR )
+ {
+ pxClient->bits.bInRename = pdFALSE_UNSIGNED;
+ }
+
+ if( pcMyReply != NULL )
+ {
+ xResult = prvSendReply( pxClient->xSocket, pcMyReply, strlen( pcMyReply ) );
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvTransferConnect( FTPClient_t *pxClient, BaseType_t xDoListen )
+{
+Socket_t xSocket;
+BaseType_t xResult;
+
+ /* Open a socket for a data connection with the FTP client.
+ Happens after a PORT or a PASV command. */
+
+ /* Make sure the previous socket is deleted and flags reset */
+ prvTransferCloseSocket( pxClient );
+
+ pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED;
+
+ xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
+
+ if( ( xSocket != FREERTOS_NO_SOCKET ) && ( xSocket != FREERTOS_INVALID_SOCKET ) )
+ {
+ BaseType_t xSmallTimeout = pdMS_TO_TICKS( 100 );
+ struct freertos_sockaddr xAddress;
+
+ #if( ipconfigFTP_TX_BUFSIZE > 0 )
+ WinProperties_t xWinProps;
+ #endif
+ xAddress.sin_addr = FreeRTOS_GetIPAddress( ); /* Single NIC, currently not used */
+ xAddress.sin_port = FreeRTOS_htons( 0 ); /* Bind to any available port number */
+
+ FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );
+
+ #if( ipconfigFTP_TX_BUFSIZE > 0 )
+ {
+ /* Fill in the buffer and window sizes that will be used by the
+ socket. */
+ xWinProps.lTxBufSize = ipconfigFTP_TX_BUFSIZE;
+ xWinProps.lTxWinSize = ipconfigFTP_TX_WINSIZE;
+ xWinProps.lRxBufSize = ipconfigFTP_RX_BUFSIZE;
+ xWinProps.lRxWinSize = ipconfigFTP_RX_WINSIZE;
+
+ /* Set the window and buffer sizes. */
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) );
+ }
+ #endif
+
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xSmallTimeout, sizeof( BaseType_t ) );
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xSmallTimeout, sizeof( BaseType_t ) );
+
+ /* The same instance of the socket will be used for the connection and
+ data transport. */
+ if( xDoListen != pdFALSE )
+ {
+ BaseType_t xTrueValue = pdTRUE;
+ FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_REUSE_LISTEN_SOCKET, ( void * ) &xTrueValue, sizeof( xTrueValue ) );
+ }
+ pxClient->bits1.bIsListen = xDoListen;
+ pxClient->xTransferSocket = xSocket;
+
+ if( xDoListen != pdFALSE )
+ {
+ FreeRTOS_FD_SET( xSocket, pxClient->pxParent->xSocketSet, eSELECT_EXCEPT | eSELECT_READ );
+ /* Calling FreeRTOS_listen( ) */
+ xResult = prvTransferStart( pxClient );
+ if( xResult >= 0 )
+ {
+ xResult = pdTRUE;
+ }
+ }
+ else
+ {
+ FreeRTOS_FD_SET( xSocket, pxClient->pxParent->xSocketSet, eSELECT_EXCEPT | eSELECT_READ | eSELECT_WRITE );
+ xResult = pdTRUE;
+ }
+ }
+ else
+ {
+ FreeRTOS_printf( ( "FreeRTOS_socket() failed\n" ) );
+ xResult = -pdFREERTOS_ERRNO_ENOMEM;
+ }
+
+ /* An active socket (PORT) should connect() later. */
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvTransferStart( FTPClient_t *pxClient )
+{
+BaseType_t xResult;
+
+ /* A transfer socket has been opened, now either call listen() for 'PASV'
+ or connect() for the 'PORT' command. */
+ if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED )
+ {
+ xResult = FreeRTOS_listen( pxClient->xTransferSocket, 1 );
+ }
+ else
+ {
+ struct freertos_sockaddr xAddress;
+
+ xAddress.sin_addr = FreeRTOS_htonl( pxClient->ulClientIP );
+ xAddress.sin_port = FreeRTOS_htons( pxClient->usClientPort );
+ /* Start an active connection for this data socket */
+ xResult = FreeRTOS_connect( pxClient->xTransferSocket, &xAddress, sizeof( xAddress ) );
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+static void prvTransferCheck( FTPClient_t *pxClient )
+{
+BaseType_t xRxSize;
+
+ /* A data transfer is busy. Check if there are changes in connectedness. */
+ xRxSize = FreeRTOS_rx_size( pxClient->xTransferSocket );
+
+ if( pxClient->bits1.bClientConnected == pdFALSE_UNSIGNED )
+ {
+ /* The time to receive a small file can be so short, that we don't even
+ see that the socket gets connected and disconnected. Therefore, check
+ the sizeof of the RX buffer. */
+ {
+ struct freertos_sockaddr xAddress;
+ Socket_t xNexSocket;
+ socklen_t xSocketLength = sizeof( xAddress );
+
+ if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED )
+ {
+ xNexSocket = FreeRTOS_accept( pxClient->xTransferSocket, &xAddress, &xSocketLength);
+ if( ( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) ) ||
+ xRxSize > 0 )
+ {
+ pxClient->bits1.bClientConnected = pdTRUE_UNSIGNED;
+ }
+ }
+ else
+ {
+ if( FreeRTOS_issocketconnected( pxClient->xTransferSocket ) > 0 ||
+ xRxSize > 0 )
+ {
+ pxClient->bits1.bClientConnected = pdTRUE_UNSIGNED;
+ }
+ }
+ if( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED )
+ {
+ pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED;
+ #if( ipconfigHAS_PRINTF != 0 )
+ {
+ struct freertos_sockaddr xRemoteAddress, xLocalAddress;
+ FreeRTOS_GetRemoteAddress( pxClient->xTransferSocket, &xRemoteAddress );
+ FreeRTOS_GetLocalAddress( pxClient->xTransferSocket, &xLocalAddress );
+ FreeRTOS_printf( ( "%s Connected from %u to %u\n",
+ pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ? "PASV" : "PORT",
+ ( unsigned ) FreeRTOS_ntohs( xLocalAddress.sin_port ),
+ ( unsigned ) FreeRTOS_ntohs( xRemoteAddress.sin_port ) ) );
+ }
+ #endif /* ipconfigHAS_PRINTF */
+ FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE );
+ FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_READ|eSELECT_EXCEPT );
+ }
+ }
+ }
+
+ if ( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED )
+ {
+ if( pxClient->pcConnectionAck[ 0 ] != '\0' )
+ {
+ BaseType_t xLength;
+ BaseType_t xRemotePort;
+ struct freertos_sockaddr xRemoteAddress;
+
+ FreeRTOS_GetRemoteAddress( pxClient->xTransferSocket, &xRemoteAddress );
+ xRemotePort = FreeRTOS_ntohs( xRemoteAddress.sin_port );
+
+ /* Tell on the command port 21 we have a data connection */
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ pxClient->pcConnectionAck, pxClient->ulClientIP, xRemotePort );
+
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+ pxClient->pcConnectionAck[ 0 ] = '\0';
+ }
+
+ if( ( FreeRTOS_issocketconnected( pxClient->xTransferSocket ) == pdFALSE ) && FreeRTOS_rx_size( pxClient->xTransferSocket ) == 0 )
+ {
+ prvTransferCloseSocket( pxClient );
+ prvTransferCloseFile( pxClient );
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvTransferCloseSocket( FTPClient_t *pxClient )
+{
+ if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET )
+ {
+ /* DEBUGGING ONLY */
+ BaseType_t xRxSize = FreeRTOS_rx_size( pxClient->xTransferSocket );
+ if( xRxSize > 0 )
+ {
+ BaseType_t xRxSize2;
+ BaseType_t xStatus;
+ prvStoreFileWork( pxClient );
+ xStatus = FreeRTOS_connstatus( pxClient->xTransferSocket );
+ xRxSize2 = FreeRTOS_rx_size( pxClient->xTransferSocket );
+ FreeRTOS_printf( ( "FTP: WARNING: %s: RX size = %ld -> %ld (%s)\n",
+ FreeRTOS_GetTCPStateName( xStatus ),
+ xRxSize, xRxSize2, pxClient->pcFileName ) );
+ if( xRxSize2 > 1 )
+ {
+ return;
+ }
+
+ /* Remove compiler warnings in case FreeRTOS_printf() is not
+ defined. */
+ ( void ) xStatus;
+ }
+ }
+
+ if( ( pxClient->pxWriteHandle != NULL ) || ( pxClient->pxReadHandle != NULL ) )
+ {
+ BaseType_t xLength;
+ char pcStrBuf[ 32 ];
+
+ if( pxClient->bits1.bHadError == pdFALSE_UNSIGNED )
+ {
+ xLength = snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ),
+ "226 Closing connection %d bytes transmitted\r\n", ( int ) pxClient->ulRecvBytes );
+ }
+ else
+ {
+ xLength = snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ),
+ "451 Requested action aborted after %d bytes\r\n", ( int ) pxClient->ulRecvBytes );
+ }
+
+ /* Tell on the command socket the data connection is now closed. */
+ prvSendReply( pxClient->xSocket, pxClient->pcClientAck, xLength );
+
+ #if( ipconfigHAS_PRINTF != 0 )
+ {
+ TickType_t xDelta;
+ uint32_t ulAverage;
+ xDelta = xTaskGetTickCount( ) - pxClient->xStartTime;
+ ulAverage = ulGetAverage( pxClient->ulRecvBytes, xDelta );
+
+ FreeRTOS_printf( ("FTP: %s: '%s' %lu Bytes (%s/sec)\n",
+ pxClient->pxReadHandle ? "sent" : "recv",
+ pxClient->pcFileName,
+ pxClient->ulRecvBytes,
+ pcMkSize( ulAverage, pcStrBuf, sizeof( pcStrBuf ) ) ) );
+ }
+ #endif
+ }
+
+ if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET )
+ {
+ FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL );
+ FreeRTOS_closesocket( pxClient->xTransferSocket );
+ pxClient->xTransferSocket = FREERTOS_NO_SOCKET;
+ if( pxClient->ulRecvBytes == 0ul )
+ {
+ /* Received zero bytes: an empty file */
+ pxClient->bits1.bEmptyFile = pdTRUE_UNSIGNED;
+ }
+ else
+ {
+ pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED;
+ }
+ }
+ pxClient->bits1.bIsListen = pdFALSE_UNSIGNED;
+ pxClient->bits1.bDirHasEntry = pdFALSE_UNSIGNED;
+ pxClient->bits1.bClientConnected = pdFALSE_UNSIGNED;
+ pxClient->bits1.bHadError = pdFALSE_UNSIGNED;
+}
+/*-----------------------------------------------------------*/
+
+static void prvTransferCloseFile( FTPClient_t *pxClient )
+{
+ if( pxClient->pxWriteHandle != NULL )
+ {
+ ff_fclose( pxClient->pxWriteHandle );
+ pxClient->pxWriteHandle = NULL;
+ #if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 )
+ {
+ vApplicationFTPReceivedHook( pxClient->pcFileName, pxClient->ulRecvBytes, pxClient );
+ }
+ #endif
+
+ }
+ if( pxClient->pxReadHandle != NULL )
+ {
+ ff_fclose( pxClient->pxReadHandle );
+ pxClient->pxReadHandle = NULL;
+ }
+ /* These two field are only used for logging / file-statistics */
+ pxClient->ulRecvBytes = 0ul;
+ pxClient->xStartTime = 0ul;
+}
+/*-----------------------------------------------------------*/
+
+/**
+ * Guess the transfer type, given the client requested type.
+ * Actually in unix there is no difference between binary and
+ * ascii mode when we work with file descriptors.
+ * If #type is not recognized as a valid client request, -1 is returned.
+ */
+static BaseType_t prvGetTransferType( const char *pcType )
+{
+BaseType_t xResult = -1;
+
+ if( pcType != NULL )
+ {
+ BaseType_t xLength = strlen( pcType );
+ if( xLength == 0 )
+ {
+ return -1;
+ }
+ switch( pcType[ 0 ] ) {
+ case 'I':
+ xResult = TMODE_BINARY;
+ break;
+ case 'A':
+ xResult = TMODE_ASCII;
+ break;
+ case 'L':
+ if( xLength >= 3 )
+ {
+ if( pcType[ 2 ] == '7' )
+ {
+ xResult = TMODE_7BITS;
+ }
+ else if( pcType[ 2 ] == '8' )
+ {
+ xResult = TMODE_7BITS;
+ }
+ }
+ break;
+ }
+ }
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigHAS_PRINTF != 0 )
+ #define SIZE_1_GB ( 1024ul * 1024ul * 1024ul )
+ #define SIZE_1_MB ( 1024ul * 1024ul )
+ #define SIZE_1_KB ( 1024ul )
+
+ static const char *pcMkSize( uint32_t ulAmount, char *pcBuffer, BaseType_t xBufferSize )
+ {
+ uint32_t ulGB, ulMB, ulKB, ulByte;
+
+ ulGB = ( ulAmount / SIZE_1_GB );
+ ulAmount -= ( ulGB * SIZE_1_GB );
+ ulMB = ( ulAmount / SIZE_1_MB );
+ ulAmount -= ( ulMB * SIZE_1_MB );
+ ulKB = ( ulAmount / SIZE_1_KB );
+ ulAmount -= ( ulKB * SIZE_1_KB );
+ ulByte = ( ulAmount );
+
+ if (ulGB != 0ul )
+ {
+ snprintf( pcBuffer, xBufferSize, "%lu.%02lu GB", ulGB, (100 * ulMB) / SIZE_1_KB );
+ }
+ else if( ulMB != 0ul )
+ {
+ snprintf( pcBuffer, xBufferSize, "%lu.%02lu MB", ulMB, (100 * ulKB) / SIZE_1_KB );
+ }
+ else if( ulKB != 0ul )
+ {
+ snprintf(pcBuffer, xBufferSize, "%lu.%02lu KB", ulKB, (100 * ulByte) / SIZE_1_KB );
+ }
+ else
+ {
+ snprintf( pcBuffer, xBufferSize, "%lu bytes", ulByte );
+ }
+
+ return pcBuffer;
+ }
+ /*-----------------------------------------------------------*/
+#endif /* ipconfigHAS_PRINTF != 0 */
+
+#if( ipconfigHAS_PRINTF != 0 )
+ static uint32_t ulGetAverage( uint32_t ulAmount, TickType_t xDeltaMs )
+ {
+ uint32_t ulAverage;
+
+ /* Get the average amount of bytes per seconds. Ideally this is
+ calculated by Multiplying with 1000 and dividing by milliseconds:
+ ulAverage = ( 1000ul * ulAmount ) / xDeltaMs;
+ Now get a maximum precision, while avoiding an arithmetic overflow:
+ */
+ if( xDeltaMs == 0ul )
+ {
+ /* Time is zero, there is no average */
+ ulAverage = 0ul;
+ }
+ else if( ulAmount >= ( ~0ul / 10ul ) )
+ {
+ /* More than 409 MB has been transferred, do not multiply. */
+ ulAverage = ( ulAmount / ( xDeltaMs / 1000ul ) );
+ }
+ else if( ulAmount >= ( ~0ul / 100ul ) )
+ {
+ /* Between 409 and 41 MB has been transferred, can multiply by 10. */
+ ulAverage = ( ( ulAmount * 10ul ) / ( xDeltaMs / 100ul ) );
+ }
+ else if( ulAmount >= ( ~0ul / 1000ul ) )
+ {
+ /* Between 4.1 MB and 41 has been transferred, can multiply by 100. */
+ ulAverage = ( ( ulAmount * 100ul ) / ( xDeltaMs / 10ul ) );
+ }
+ else
+ {
+ /* Less than 4.1 MB: can multiply by 1000. */
+ ulAverage = ( ( ulAmount * 1000ul ) / xDeltaMs );
+ }
+
+ return ulAverage;
+ }
+ /*-----------------------------------------------------------*/
+#endif /* ipconfigHAS_PRINTF != 0 */
+
+static UBaseType_t prvParsePortData( const char *pcCommand, uint32_t *pulIPAddress )
+{
+/*_HT_ Using 'unsigned' here because when sscanf() sees '%u', it expects a pointer to 'unsigned'.
+Not sure about the sscanf() format for UBaseType_t ? */
+unsigned h1, h2, h3, h4, p1, p2;
+char sep;
+UBaseType_t uxResult;
+
+ /* Expect PORT h1,h2,h3,h4,p1,p2 */
+ if (sscanf (pcCommand, "%u%c%u%c%u%c%u%c%u%c%u", &h1, &sep, &h2, &sep, &h3, &sep, &h4, &sep, &p1, &sep, &p2) != 11)
+ {
+ uxResult= 0u;
+ }
+ else
+ {
+ /* Put in network byte order. */
+ *pulIPAddress =
+ ( ( uint32_t ) h1 << 24 ) |
+ ( ( uint32_t ) h2 << 16 ) |
+ ( ( uint32_t ) h3 << 8 ) |
+ ( ( uint32_t ) h4 );
+ uxResult = ( p1 << 8 ) | p2;
+ }
+ return uxResult;
+}
+/*-----------------------------------------------------------*/
+
+/*
+
+ #### ####### # ###
+# # # # ## # #
+# # # # # #
+# ###### #### ### ## #### # # ### # ####
+ ## # # # # # # # # ##### # # # #
+ ## # # # ## # ###### # # # # ######
+# # # # # # # # # # #
+# # # ## # # # # ## # # # # ##
+ #### ## #### #### #### #### ##### ##### ####
+
+*/
+
+static BaseType_t prvStoreFilePrep( FTPClient_t *pxClient, char *pcFileName )
+{
+BaseType_t xResult;
+FF_FILE *pxNewHandle;
+size_t uxFileSize = 0ul;
+int iErrorNo;
+
+ /* Close previous handle (if any) and reset file transfer parameters. */
+ prvTransferCloseFile( pxClient );
+
+ xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName );
+
+ pxNewHandle = NULL;
+
+ if( pxClient->ulRestartOffset != 0 )
+ {
+ size_t uxOffset = pxClient->ulRestartOffset;
+ int32_t lRc;
+
+ pxClient->ulRestartOffset = 0ul; /* Only use 1 time. */
+ pxNewHandle = ff_fopen( pxClient->pcFileName, "ab" );
+
+ if( pxNewHandle != NULL )
+ {
+ uxFileSize = pxNewHandle->ulFileSize;
+
+ if( uxOffset <= uxFileSize )
+ {
+ lRc = ff_fseek( pxNewHandle, uxOffset, FF_SEEK_SET );
+ }
+ else
+ {
+ /* Won't even try to seek after EOF */
+ lRc = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ if( lRc != 0 )
+ {
+ BaseType_t xLength;
+
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "450 Seek invalid %u length %u\r\n",
+ ( unsigned ) uxOffset, ( unsigned ) uxFileSize );
+
+ /* "Requested file action not taken". */
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+
+ FreeRTOS_printf( ( "ftp::storeFile: create %s: Seek %u length %u\n",
+ pxClient->pcFileName, ( unsigned ) uxOffset, ( unsigned ) uxFileSize ) );
+
+ ff_fclose( pxNewHandle );
+ pxNewHandle = NULL;
+ }
+ }
+ }
+ else
+ {
+ pxNewHandle = ff_fopen( pxClient->pcFileName, "wb" );
+ }
+
+ if( pxNewHandle == NULL )
+ {
+ iErrorNo = stdioGET_ERRNO();
+ if( iErrorNo == pdFREERTOS_ERRNO_ENOSPC )
+ {
+ prvSendReply( pxClient->xSocket, REPL_552, 0 );
+ }
+ else
+ {
+ /* "Requested file action not taken". */
+ prvSendReply( pxClient->xSocket, REPL_450, 0 );
+ }
+ FreeRTOS_printf( ( "ftp::storeFile: create %s: %s (errno %d)\n",
+ pxClient->pcFileName,
+ ( const char* ) strerror( iErrorNo ), iErrorNo ) );
+
+ xResult = pdFALSE;
+ }
+ else
+ {
+ if( pxClient->bits1.bIsListen )
+ {
+ /* True if PASV is used. */
+ snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ),
+ "150 Accepted data connection from %%xip:%%u\r\n" );
+ prvTransferCheck( pxClient );
+ }
+ else
+ {
+ BaseType_t xLength;
+
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "150 Opening BIN connection to store file\r\n" );
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+ pxClient->pcConnectionAck[ 0 ] = '\0';
+ prvTransferStart( pxClient ); /* Now active connect. */
+ }
+
+ pxClient->pxWriteHandle = pxNewHandle;
+
+ /* To get some statistics about the performance. */
+ pxClient->xStartTime = xTaskGetTickCount( );
+
+ xResult = pdTRUE;
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigFTP_ZERO_COPY_ALIGNED_WRITES == 0 )
+
+ static BaseType_t prvStoreFileWork( FTPClient_t *pxClient )
+ {
+ BaseType_t xRc, xWritten;
+
+ /* Read from the data socket until all has been read or until a negative value
+ is returned. */
+ for( ; ; )
+ {
+ char *pcBuffer;
+
+ /* The "zero-copy" method: */
+ xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) &pcBuffer,
+ 0x20000u, FREERTOS_ZERO_COPY | FREERTOS_MSG_DONTWAIT );
+ if( xRc <= 0 )
+ {
+ break;
+ }
+ pxClient->ulRecvBytes += xRc;
+ xWritten = ff_fwrite( pcBuffer, 1, xRc, pxClient->pxWriteHandle );
+ FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) NULL, xRc, 0 );
+ if( xWritten != xRc )
+ {
+ xRc = -1;
+ /* bHadError: a transfer got aborted because of an error. */
+ pxClient->bits1.bHadError = pdTRUE_UNSIGNED;
+ break;
+ }
+ }
+ return xRc;
+ }
+
+#else /* ipconfigFTP_ZERO_COPY_ALIGNED_WRITES != 0 */
+
+ #if !defined( ipconfigFTP_PREFERRED_WRITE_SIZE )
+ /* If you store data on flash, it may be profitable to give 'ipconfigFTP_PREFERRED_WRITE_SIZE'
+ the same size as the size of the flash' erase blocks, e.g. 4KB */
+ #define ipconfigFTP_PREFERRED_WRITE_SIZE 512ul
+ #endif
+
+ static BaseType_t prvStoreFileWork( FTPClient_t *pxClient )
+ {
+ BaseType_t xRc, xWritten;
+
+ /* Read from the data socket until all has been read or until a negative
+ value is returned. */
+ for( ; ; )
+ {
+ char *pcBuffer;
+ UBaseType_t xStatus;
+
+ /* The "zero-copy" method: */
+ xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) &pcBuffer,
+ 0x20000u, FREERTOS_ZERO_COPY | FREERTOS_MSG_DONTWAIT );
+
+ if( xRc <= 0 )
+ {
+ /* There are no data or the connection is closed. */
+ break;
+ }
+ xStatus = FreeRTOS_connstatus( pxClient->xTransferSocket );
+ if( xStatus != eESTABLISHED )
+ {
+ /* The connection is not established (any more), therefore
+ accept any amount of bytes, probably the last few bytes. */
+ }
+ else
+ {
+ if( xRc >= ipconfigFTP_PREFERRED_WRITE_SIZE )
+ {
+ /* More than a sector to write, round down to a multiple of
+ PREFERRED_WRITE_SIZE bytes. */
+ xRc = ( xRc / ipconfigFTP_PREFERRED_WRITE_SIZE ) * ipconfigFTP_PREFERRED_WRITE_SIZE;
+ }
+ else
+ {
+ const StreamBuffer_t *pxBuffer = FreeRTOS_get_rx_buf( pxClient->xTransferSocket );
+ size_t uxSpace = pxBuffer->LENGTH - pxBuffer->uxTail;
+
+ if( uxSpace >= ipconfigFTP_PREFERRED_WRITE_SIZE )
+ {
+ /* At this moment there are les than PREFERRED_WRITE_SIZE bytes in the RX
+ buffer, but there is space for more. Just return and
+ wait for more. */
+ xRc = 0;
+ }
+ else
+ {
+ /* Now reading beyond the end of the circular buffer,
+ use a normal read. */
+ pcBuffer = pcFILE_BUFFER;
+ xRc = FreeRTOS_recvcount( pxClient->xTransferSocket );
+ xRc = ( xRc / ipconfigFTP_PREFERRED_WRITE_SIZE ) * ipconfigFTP_PREFERRED_WRITE_SIZE;
+ if( xRc > 0 )
+ {
+ xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) pcBuffer,
+ sizeof( pcFILE_BUFFER ), FREERTOS_MSG_DONTWAIT );
+ }
+ }
+ }
+ }
+ if( xRc == 0 )
+ {
+ break;
+ }
+ pxClient->ulRecvBytes += xRc;
+
+ xWritten = ff_fwrite( pcBuffer, 1, xRc, pxClient->pxWriteHandle );
+ if( pcBuffer != pcFILE_BUFFER )
+ {
+ FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) NULL, xRc, 0 );
+ }
+ if( xWritten != xRc )
+ {
+ xRc = -1;
+ /* bHadError: a transfer got aborted because of an error. */
+ pxClient->bits1.bHadError = pdTRUE_UNSIGNED;
+ break;
+ }
+ }
+ return xRc;
+ }
+
+#endif /* ipconfigFTP_ZERO_COPY_ALIGNED_WRITES */
+/*-----------------------------------------------------------*/
+
+/*
+###### # ####### # ###
+ # # # # # ## # #
+ # # # # # #
+ # # #### ###### ### ## ### #### # # #### # # ### # ####
+ ###### # # # # # # # # # # # # # ##### # # # #
+ # ## ###### # ## # # ###### # # ###### # # # # ######
+ # # # # # # # # # # # # # #
+ # # # ## # ## # # # ## # # # ## # # # # ##
+### ## #### ## #### ##### #### ## #### #### ##### ##### ####
+*/
+static BaseType_t prvRetrieveFilePrep( FTPClient_t *pxClient, char *pcFileName )
+{
+BaseType_t xResult = pdTRUE;
+size_t uxFileSize;
+
+ /* Close previous handle (if any) and reset file transfer parameters */
+ prvTransferCloseFile( pxClient );
+
+ xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName );
+
+ pxClient->pxReadHandle = ff_fopen( pxClient->pcFileName, "rb" );
+ if( pxClient->pxReadHandle == NULL )
+ {
+ int iErrno = stdioGET_ERRNO();
+ /* "Requested file action not taken". */
+ prvSendReply( pxClient->xSocket, REPL_450, 0 );
+ FreeRTOS_printf( ("prvRetrieveFilePrep: open '%s': errno %d: %s\n",
+ pxClient->pcFileName, iErrno, ( const char * ) strerror( iErrno ) ) );
+ uxFileSize = 0ul;
+ xResult = pdFALSE;
+ }
+ else
+ {
+ uxFileSize = pxClient->pxReadHandle->ulFileSize;
+ pxClient->uxBytesLeft = uxFileSize;
+ if( pxClient->ulRestartOffset != 0ul )
+ {
+ size_t uxOffset = pxClient->ulRestartOffset;
+ int32_t iRc;
+
+ /* Only use 1 time. */
+ pxClient->ulRestartOffset = 0;
+
+ if( uxOffset < uxFileSize )
+ {
+ iRc = ff_fseek( pxClient->pxReadHandle, uxOffset, FF_SEEK_SET );
+ }
+ else
+ {
+ iRc = -pdFREERTOS_ERRNO_EINVAL;
+ }
+ if( iRc != 0 )
+ {
+ BaseType_t xLength;
+
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "450 Seek invalid %u length %u\r\n", ( unsigned ) uxOffset, ( unsigned ) uxFileSize );
+
+ /* "Requested file action not taken". */
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+
+ FreeRTOS_printf( ( "prvRetrieveFilePrep: create %s: Seek %u length %u\n",
+ pxClient->pcFileName, ( unsigned ) uxOffset, ( unsigned ) uxFileSize ) );
+
+ ff_fclose( pxClient->pxReadHandle );
+ pxClient->pxReadHandle = NULL;
+ xResult = pdFALSE;
+ }
+ else
+ {
+ pxClient->uxBytesLeft = uxFileSize - pxClient->ulRestartOffset;
+ }
+ }
+ }
+ if( xResult != pdFALSE )
+ {
+ if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED )
+ {
+ /* True if PASV is used. */
+ snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ),
+ "150%cAccepted data connection from %%xip:%%u\r\n%s",
+ pxClient->xTransType == TMODE_ASCII ? '-' : ' ',
+ pxClient->xTransType == TMODE_ASCII ? "150 NOTE: ASCII mode requested, but binary mode used\r\n" : "" );
+ } else {
+ BaseType_t xLength;
+
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "150%cOpening data connection to %lxip:%u\r\n%s",
+ pxClient->xTransType == TMODE_ASCII ? '-' : ' ',
+ pxClient->ulClientIP,
+ pxClient->usClientPort,
+ pxClient->xTransType == TMODE_ASCII ? "150 NOTE: ASCII mode requested, but binary mode used\r\n" : "" );
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+ pxClient->pcConnectionAck[ 0 ] = '\0';
+ prvTransferStart( pxClient );
+ }
+
+ /* Prepare the ACK which will be sent when all data has been sent. */
+ snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), "%s", REPL_226 );
+
+ /* To get some statistics about the performance. */
+ pxClient->xStartTime = xTaskGetTickCount( );
+ if( uxFileSize == 0ul )
+ {
+ FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR );
+ }
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvRetrieveFileWork( FTPClient_t *pxClient )
+{
+size_t uxSpace;
+size_t uxCount, uxItemsRead;
+BaseType_t xRc = 0;
+BaseType_t xSetEvent = pdFALSE;
+
+ do
+ {
+ #if( ipconfigFTP_TX_ZERO_COPY != 0 )
+ char *pcBuffer;
+ BaseType_t xBufferLength;
+ #endif /* ipconfigFTP_TX_ZERO_COPY */
+
+ /* Take the lesser of the two: tx_space (number of bytes that can be
+ queued for transmission) and uxBytesLeft (the number of bytes left to
+ read from the file) */
+ uxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket );
+
+ if( uxSpace == 0 )
+ {
+ FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE | eSELECT_EXCEPT );
+ xRc = FreeRTOS_select( pxClient->pxParent->xSocketSet, 200 );
+ uxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket );
+ }
+
+ uxCount = FreeRTOS_min_uint32( pxClient->uxBytesLeft, uxSpace );
+
+ if( uxCount == 0 )
+ {
+ break;
+ }
+
+ #if( ipconfigFTP_TX_ZERO_COPY == 0 )
+ {
+ if( uxCount > sizeof( pcFILE_BUFFER ) )
+ {
+ uxCount = sizeof( pcFILE_BUFFER );
+ }
+ uxItemsRead = ff_fread( pcFILE_BUFFER, 1, uxCount, pxClient->pxReadHandle );
+ if( uxItemsRead != uxCount )
+ {
+ FreeRTOS_printf( ( "prvRetrieveFileWork: Got %u Expected %u\n", ( unsigned )uxItemsRead, ( unsigned ) uxCount ) );
+ xRc = FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR );
+ pxClient->uxBytesLeft = 0u;
+ break;
+ }
+ pxClient->uxBytesLeft -= uxCount;
+
+ if( pxClient->uxBytesLeft == 0u )
+ {
+ BaseType_t xTrueValue = 1;
+
+ FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) );
+ }
+
+ xRc = FreeRTOS_send( pxClient->xTransferSocket, pcFILE_BUFFER, uxCount, 0 );
+ }
+ #else /* ipconfigFTP_TX_ZERO_COPY != 0 */
+ {
+ /* Use zero-copy transmission:
+ FreeRTOS_get_tx_head() returns a direct pointer to the TX stream and
+ set xBufferLength to know how much space there is left. */
+ pcBuffer = ( char * )FreeRTOS_get_tx_head( pxClient->xTransferSocket, &xBufferLength );
+ if( ( pcBuffer != NULL ) && ( xBufferLength >= 512 ) )
+ {
+ /* Will read disk data directly to the TX stream of the socket. */
+ uxCount = FreeRTOS_min_uint32( uxCount, ( uint32_t )xBufferLength );
+ if( uxCount > ( size_t ) 0x40000u )
+ {
+ uxCount = ( size_t ) 0x40000u;
+ }
+ }
+ else
+ {
+ /* Use the normal file i/o buffer. */
+ pcBuffer = pcFILE_BUFFER;
+ if( uxCount > sizeof( pcFILE_BUFFER ) )
+ {
+ uxCount = sizeof( pcFILE_BUFFER );
+ }
+ }
+
+ if ( pxClient->uxBytesLeft >= 1024u )
+ {
+ uxCount &= ~( ( size_t ) 512u - 1u );
+ }
+
+ if( uxCount <= 0u )
+ {
+ /* Nothing to send after rounding down to a multiple of a sector size. */
+ break;
+ }
+
+ uxItemsRead = ff_fread( pcBuffer, 1, uxCount, pxClient->pxReadHandle );
+
+ if( uxCount != uxItemsRead )
+ {
+ FreeRTOS_printf( ( "prvRetrieveFileWork: Got %u Expected %u\n", ( unsigned )uxItemsRead, ( unsigned )uxCount ) );
+ xRc = FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR );
+ pxClient->uxBytesLeft = 0u;
+ break;
+ }
+ pxClient->uxBytesLeft -= uxCount;
+
+ if( pxClient->uxBytesLeft == 0u )
+ {
+ BaseType_t xTrueValue = 1;
+
+ FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) );
+ }
+ if( pcBuffer != pcFILE_BUFFER )
+ {
+ pcBuffer = NULL;
+ }
+ xRc = FreeRTOS_send( pxClient->xTransferSocket, pcBuffer, uxCount, 0 );
+ }
+ #endif /* ipconfigFTP_TX_ZERO_COPY */
+
+ if( xRc < 0 )
+ {
+ break;
+ }
+
+ pxClient->ulRecvBytes += xRc;
+ if( pxClient->uxBytesLeft == 0u )
+ {
+ break;
+ }
+ } while( uxCount > 0u );
+
+ if( xRc < 0 )
+ {
+ FreeRTOS_printf( ( "prvRetrieveFileWork: already disconnected\n" ) );
+ }
+ else if( pxClient->uxBytesLeft <= 0u )
+ {
+ BaseType_t x;
+
+ for( x = 0; x < 5; x++ )
+ {
+ xRc = FreeRTOS_recv( pxClient->xTransferSocket, pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), 0 );
+ if( xRc < 0 )
+ {
+ break;
+ }
+ }
+// FreeRTOS_printf( ( "prvRetrieveFileWork: %s all sent: xRc %ld\n", pxClient->pcFileName, xRc ) );
+ }
+ else
+ {
+ FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE );
+ xSetEvent = pdTRUE;
+ }
+ if( xSetEvent == pdFALSE )
+ {
+ FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE );
+ }
+ return xRc;
+}
+/*-----------------------------------------------------------*/
+
+/*
+### ##### #### #####
+ # # # # # # #
+ # # # # #
+ # # # #
+ # # ## #
+ # # # ## #
+ # # # # # #
+ # # # # # #
+####### ##### #### ####
+*/
+/* Prepare sending a directory LIST */
+static BaseType_t prvListSendPrep( FTPClient_t *pxClient )
+{
+BaseType_t xFindResult;
+int iErrorNo;
+
+ if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED )
+ {
+ /* True if PASV is used */
+ snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ),
+ "150 Accepted data connection from %%xip:%%u\r\n" );
+ }
+ else
+ {
+ BaseType_t xLength;
+
+ /* Here the FTP server is supposed to connect() */
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "150 Opening ASCII mode data connection to for /bin/ls \r\n" );
+
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+ /* Clear the current connection acknowledge message */
+ pxClient->pcConnectionAck[ 0 ] = '\0';
+ prvTransferStart( pxClient );
+ }
+
+ pxClient->xDirCount = 0;
+ xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pxClient->pcCurrentDir );
+
+ xFindResult = ff_findfirst( pcNEW_DIR, &pxClient->xFindData );
+
+ pxClient->bits1.bDirHasEntry = ( xFindResult >= 0 );
+
+ iErrorNo = stdioGET_ERRNO();
+ if( ( xFindResult < 0 ) && ( iErrorNo == pdFREERTOS_ERRNO_ENMFILE ) )
+ {
+ FreeRTOS_printf( ("prvListSendPrep: Empty directory? (%s)\n", pxClient->pcCurrentDir ) );
+ prvSendReply( pxClient->xTransferSocket, "total 0\r\n", 0 );
+ pxClient->xDirCount++;
+ }
+ else if( xFindResult < 0 )
+ {
+ FreeRTOS_printf( ( "prvListSendPrep: rc = %ld iErrorNo = %d\n", xFindResult, iErrorNo ) );
+ prvSendReply( pxClient->xSocket, REPL_451, 0 );
+ }
+ pxClient->pcClientAck[ 0 ] = '\0';
+
+ return pxClient->xDirCount;
+}
+/*-----------------------------------------------------------*/
+
+#define MAX_DIR_LIST_ENTRY_SIZE 256
+
+static BaseType_t prvListSendWork( FTPClient_t *pxClient )
+{
+BaseType_t xTxSpace;
+
+ while( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED )
+ {
+ char *pcWritePtr = pcCOMMAND_BUFFER;
+ BaseType_t xWriteLength;
+
+ xTxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket );
+
+ if( xTxSpace > ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) )
+ {
+ xTxSpace = sizeof( pcCOMMAND_BUFFER );
+ }
+
+ while( ( xTxSpace >= MAX_DIR_LIST_ENTRY_SIZE ) && ( pxClient->bits1.bDirHasEntry != pdFALSE_UNSIGNED ) )
+ {
+ BaseType_t xLength, xEndOfDir;
+ int32_t iRc;
+ int iErrorNo;
+
+ xLength = prvGetFileInfoStat( &( pxClient->xFindData.xDirectoryEntry ), pcWritePtr, xTxSpace );
+
+ pxClient->xDirCount++;
+ pcWritePtr += xLength;
+ xTxSpace -= xLength;
+
+ iRc = ff_findnext( &pxClient->xFindData );
+ iErrorNo = stdioGET_ERRNO();
+
+ xEndOfDir = ( iRc < 0 ) && ( iErrorNo == pdFREERTOS_ERRNO_ENMFILE );
+
+ pxClient->bits1.bDirHasEntry = ( xEndOfDir == pdFALSE ) && ( iRc >= 0 );
+
+ if( ( iRc < 0 ) && ( xEndOfDir == pdFALSE ) )
+ {
+ FreeRTOS_printf( ("prvListSendWork: %s (rc %08x)\n",
+ ( const char * ) strerror( iErrorNo ),
+ ( unsigned )iRc ) );
+ }
+ }
+ xWriteLength = ( BaseType_t ) ( pcWritePtr - pcCOMMAND_BUFFER );
+
+ if( xWriteLength == 0 )
+ {
+ break;
+ }
+
+ if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED )
+ {
+ uint32_t ulTotalCount;
+ uint32_t ulFreeCount;
+ uint32_t ulPercentage;
+
+ ulTotalCount = 1;
+ ulFreeCount = ff_diskfree( pxClient->pcCurrentDir, &ulTotalCount );
+ ulPercentage = ( uint32_t ) ( ( 100ULL * ulFreeCount + ulTotalCount / 2 ) / ulTotalCount );
+
+ /* Prepare the ACK which will be sent when all data has been sent. */
+ snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ),
+ "226-Options: -l\r\n"
+ "226-%ld matches total\r\n"
+ "226 Total %lu KB (%lu %% free)\r\n",
+ pxClient->xDirCount, ulTotalCount /1024, ulPercentage );
+ }
+
+ if( xWriteLength )
+ {
+ if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED )
+ {
+ BaseType_t xTrueValue = 1;
+
+ FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) );
+ }
+
+ prvSendReply( pxClient->xTransferSocket, pcCOMMAND_BUFFER, xWriteLength );
+ }
+
+ if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED )
+ {
+ prvSendReply( pxClient->xSocket, pxClient->pcClientAck, 0 );
+ break;
+ }
+
+ } /* while( pxClient->bits1.bClientConnected ) */
+
+ return 0;
+}
+/*-----------------------------------------------------------*/
+
+static const char *pcMonthAbbrev( BaseType_t xMonth )
+{
+static const char pcMonthList[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+ if( xMonth < 1 || xMonth > 12 )
+ xMonth = 12;
+
+ return pcMonthList + 3 * ( xMonth - 1 );
+};
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvGetFileInfoStat( FF_DirEnt_t *pxEntry, char *pcLine, BaseType_t xMaxLength )
+{
+ char date[ 16 ];
+ char mode[ 11 ] = "----------";
+ BaseType_t st_nlink = 1;
+ const char user[ 9 ] = "freertos";
+ const char group[ 8 ] = "plusfat";
+
+/*
+ * Creates a unix-style listing, understood by most FTP clients:
+ *
+ * -rw-rw-r-- 1 freertos FreeRTOS+FAT 10564588 Sep 01 00:17 03. Metaharmoniks - Star (Instrumental).mp3
+ * -rw-rw-r-- 1 freertos FreeRTOS+FAT 19087839 Sep 01 00:17 04. Simon Le Grec - Dimitri (Wherever U Are) (Cosmos Mix).mp3
+ * -rw-rw-r-- 1 freertos FreeRTOS+FAT 11100621 Sep 01 00:16 05. D-Chill - Mistake (feat. Katy Blue).mp3
+ */
+
+ #if ( ffconfigTIME_SUPPORT == 1 )
+ const FF_SystemTime_t *pxCreateTime = &( pxEntry->xCreateTime );
+ #else
+ #warning Do not use this.
+ FF_SystemTime_t xCreateTime;
+ const FF_SystemTime_t *pxCreateTime = &xCreateTime;
+ #endif
+ size_t ulSize = ( size_t )pxEntry->ulFileSize;
+ const char *pcFileName = pxEntry->pcFileName;
+
+ mode[ 0 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_DIR ) != 0 ) ? 'd' : '-';
+ #if( ffconfigDEV_SUPPORT != 0 )
+ {
+ if( ( pxEntry->ucAttrib & FF_FAT_ATTR_DIR ) == 0 )
+ {
+ switch( pxEntry->ucIsDeviceDir )
+ {
+ case FF_DEV_CHAR_DEV:
+ mode[ 0 ] = 'c';
+ break;
+ case FF_DEV_BLOCK_DEV:
+ mode[ 0 ] = 'b';
+ break;
+ }
+ }
+ }
+ #endif /* ffconfigDEV_SUPPORT != 0 */
+
+ mode[ 1 ] = 'r'; /* Owner. */
+ mode[ 2 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) ? '-' : 'w';
+ mode[ 3 ] = '-'; /* x for executable. */
+
+ mode[ 4 ] = 'r'; /* group. */
+ mode[ 5 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) ? '-' : 'w';
+ mode[ 6 ] = '-'; /* x for executable. */
+
+ mode[ 7 ] = 'r'; /* world. */
+ mode[ 8 ] = '-';
+ mode[ 9 ] = '-'; /* x for executable. */
+
+ if( pxCreateTime->Month && pxCreateTime->Day )
+ {
+ snprintf( date, sizeof( date ), "%-3.3s %02d %02d:%02d",
+ pcMonthAbbrev( pxCreateTime->Month ),
+ pxCreateTime->Day,
+ pxCreateTime->Hour,
+ pxCreateTime->Minute );
+ }
+ else
+ {
+ snprintf (date, sizeof( date ), "Jan 01 1970");
+ }
+ return snprintf( pcLine, xMaxLength, "%s %3ld %-4s %-4s %8d %12s %s\r\n",
+ mode, st_nlink, user, group, ( int ) ulSize, date, pcFileName );
+}
+/*-----------------------------------------------------------*/
+
+/*
+ #### # # #####
+ # # # # # #
+# # # # # #
+# # # # # #
+# # # # # #
+# # # # # #
+# # ## ## # #
+ # # ## ## # #
+ #### ## ## #####
+*/
+static BaseType_t prvChangeDir( FTPClient_t *pxClient, char *pcDirectory )
+{
+BaseType_t xResult;
+BaseType_t xIsRootDir, xLength, xValid;
+BaseType_t xIsDotDir = 0;
+
+ if( pcDirectory[ 0 ] == '.' )
+ {
+ if( ( pcDirectory[ 1 ] == '.' ) &&
+ ( pcDirectory[ 2 ] == '\0' ) )
+ {
+ xIsDotDir = 2;
+ }
+ else if( pcDirectory[ 1 ] == '\0' )
+ {
+ xIsDotDir = 1;
+ }
+ }
+
+ if( xIsDotDir != 0 )
+ {
+ strcpy( pcFILE_BUFFER, pxClient->pcCurrentDir );
+
+ if( pcDirectory[ 1 ] == '.' )
+ {
+ char *p = strrchr( pcFILE_BUFFER, '/' );
+ if( p != NULL )
+ {
+ if( p == pcFILE_BUFFER )
+ {
+ p[ 1 ] = '\0';
+ }
+ else
+ {
+ p[ 0 ] = '\0';
+ }
+ }
+ }
+ }
+ else
+ {
+ if(pcDirectory[ 0 ] != '/' )
+ {
+ BaseType_t xCurLength;
+
+ xCurLength = strlen( pxClient->pcCurrentDir );
+ snprintf( pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), "%s%s%s",
+ pxClient->pcCurrentDir,
+ pxClient->pcCurrentDir[ xCurLength - 1 ] == '/' ? "" : "/",
+ pcDirectory );
+ }
+ else
+ {
+ snprintf( pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), "%s", pcDirectory );
+ }
+ }
+
+ xIsRootDir = ( pcFILE_BUFFER[ 0 ] == '/' ) && ( pcFILE_BUFFER[ 1 ] == '\0' );
+ xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcFILE_BUFFER );
+
+ if( ( ( xIsRootDir == pdFALSE ) || ( FF_FS_Count() == 0 ) ) && ( ff_finddir( pcNEW_DIR ) == pdFALSE ) )
+ {
+ xValid = pdFALSE;
+ }
+ else
+ {
+ xValid = pdTRUE;
+ }
+
+ if( xValid == pdFALSE )
+ {
+ /* Get the directory cluster, if it exists. */
+ FreeRTOS_printf( ("FTP: chdir \"%s\": No such dir\n", pcNEW_DIR ) );
+ //#define REPL_550 "550 Requested action not taken.\r\n"
+ //550 /home/hein/arch/h8300: No such file or directory
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "550 %s: No such file or directory\r\n",
+ pcNEW_DIR );
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+ xResult = pdFALSE;
+ }
+ else
+ {
+ memcpy( pxClient->pcCurrentDir, pcNEW_DIR, sizeof( pxClient->pcCurrentDir ) );
+
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "250 Changed to %s\r\n", pcNEW_DIR );
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+ xResult = pdTRUE;
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+/*
+###### ## # ####### ######
+ # # ## # # ## # #
+ # # ## # # # # #
+ # # ### # # # # #
+ ###### # ## # ##### ######
+ # ## # ## # # # # ##
+ # # # ### # # #
+ # # # ## # # #
+### ## # ## #### ### ##
+*/
+static BaseType_t prvRenameFrom( FTPClient_t *pxClient, const char *pcFileName )
+{
+const char *myReply;
+FF_FILE *fh;
+
+ xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName );
+
+ myReply = NULL;
+
+ fh = ff_fopen( pxClient->pcFileName, "rb" );
+
+ if( fh != NULL )
+ {
+ ff_fclose( fh );
+ /* REPL_350; "350 Requested file action pending further information." */
+ snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "350 Rename '%s' ...\r\n", pxClient->pcFileName );
+ myReply = pcCOMMAND_BUFFER;
+ pxClient->bits.bInRename = pdTRUE_UNSIGNED;
+ }
+ else if( stdioGET_ERRNO() == pdFREERTOS_ERRNO_EISDIR )
+ {
+ snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "350 Rename directory '%s' ...\r\n", pxClient->pcFileName );
+ myReply = pcCOMMAND_BUFFER;
+ pxClient->bits.bInRename = pdTRUE_UNSIGNED;
+ }
+ else
+ {
+ FreeRTOS_printf( ("ftp::renameFrom[%s]\n%s\n", pxClient->pcFileName, strerror( stdioGET_ERRNO() ) ) );
+ myReply = REPL_451; /* "451 Requested action aborted. Local error in processing." */
+ }
+ if( myReply )
+ {
+ prvSendReply( pxClient->xSocket, myReply, 0 );
+ }
+
+ return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+/*
+###### ## # ##### ###
+ # # ## # # # # ## ##
+ # # ## # # ## ##
+ # # ### # # # #
+ ###### # ## # # # #
+ # ## # ## # # # #
+ # # # ### # ## ##
+ # # # ## # ## ##
+### ## # ## #### ###
+*/
+static BaseType_t prvRenameTo( FTPClient_t *pxClient, const char *pcFileName )
+{
+const char *myReply = NULL;
+int iResult;
+
+ xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcFileName );
+
+ /* FreeRTOS+FAT rename has an extra parameter: "remove target if already
+ exists". */
+ iResult = ff_rename( pxClient->pcFileName, pcNEW_DIR, pdFALSE );
+
+ if( iResult < 0 )
+ {
+ iResult = stdioGET_ERRNO();
+ }
+ else
+ {
+ iResult = 0;
+ }
+
+ switch( iResult )
+ {
+ case 0:
+ FreeRTOS_printf( ( "ftp::renameTo[%s,%s]: Ok\n", pxClient->pcFileName, pcNEW_DIR ) );
+ snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "250 Rename successful to '%s'\r\n", pcNEW_DIR );
+ myReply = pcCOMMAND_BUFFER;
+ break;
+ case pdFREERTOS_ERRNO_EEXIST:
+ /* the destination file already exists.
+ "450 Requested file action not taken.\r\n"*/
+ snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "450 Already exists '%s'\r\n", pcNEW_DIR );
+ myReply = pcCOMMAND_BUFFER;
+ break;
+ case pdFREERTOS_ERRNO_EIO: /* FF_ERR_FILE_COULD_NOT_CREATE_DIRENT */
+ /* if dirent creation failed (fatal error!).
+ "553 Requested action not taken.\r\n" */
+ FreeRTOS_printf( ("ftp::renameTo[%s,%s]: Error creating DirEnt\n",
+ pxClient->pcFileName, pcNEW_DIR ) );
+ myReply = REPL_553;
+ break;
+ case pdFREERTOS_ERRNO_ENXIO:
+ case pdFREERTOS_ERRNO_ENOENT:
+ /* if the source file was not found.
+ "450 Requested file action not taken.\r\n" */
+ snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "450 No such file '%s'\r\n", pxClient->pcFileName );
+ myReply = pcCOMMAND_BUFFER;
+ break;
+ default:
+ FreeRTOS_printf( ("ftp::renameTo[%s,%s]: %s\n", pxClient->pcFileName, pcNEW_DIR,
+ (const char*)strerror( stdioGET_ERRNO() ) ) );
+ myReply = REPL_451; /* "451 Requested action aborted. Local error in processing." */
+ break;
+ }
+ prvSendReply( pxClient->xSocket, myReply, 0 );
+
+ return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ #### #
+# # # #
+# # #
+# ### ###### ####
+ ## # # # #
+ ## # # ######
+# # # # #
+# # # # ## # ##
+ #### ##### ## ####
+*/
+static BaseType_t prvSiteCmd( FTPClient_t *pxClient, char *pcRestCommand )
+{
+ ( void ) pxClient;
+ ( void ) pcRestCommand;
+
+ return 0;
+}
+/*-----------------------------------------------------------*/
+
+/*
+##### ###
+ # # # #
+ # # # #
+ # # #### # #### ###### ####
+ # # # # # # # # # #
+ # # ###### # ###### # ######
+ # # # # # # #
+ # # # ## # # ## # ## # ##
+##### #### ##### #### ## ####
+*/
+static BaseType_t prvDeleteFile( FTPClient_t *pxClient, char *pcFileName )
+{
+BaseType_t xResult, xLength;
+int32_t iRc;
+int iErrorNo;
+
+ /* DELE: Delete a file. */
+ xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName );
+
+ iRc = ff_remove( pxClient->pcFileName );
+
+ if (iRc >= 0 )
+ {
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "250 File \"%s\" removed\r\n", pxClient->pcFileName );
+ xResult = pdTRUE;
+ }
+ else
+ {
+ const char *errMsg = "other error";
+
+ iErrorNo = stdioGET_ERRNO();
+ switch( iErrorNo )
+ { /*_RB_ What do these negative numbers relate to? */
+ case pdFREERTOS_ERRNO_ENOENT: errMsg = "No such file"; break; /* -31 File was not found. */
+ case pdFREERTOS_ERRNO_EALREADY: errMsg = "File still open"; break; /* -30 File is in use. */
+ case pdFREERTOS_ERRNO_EISDIR: errMsg = "Is a dir"; break; /* -32 Tried to FF_Open() a Directory. */
+ case pdFREERTOS_ERRNO_EROFS: errMsg = "Read-only"; break; /* -33 Tried to FF_Open() a file marked read only. */
+ case pdFREERTOS_ERRNO_ENOTDIR: errMsg = "Invalid path"; break; /* -34 The path of the file was not found. */
+ }
+ FreeRTOS_printf( ( "ftp::delFile: '%s' because %s\n",
+ pxClient->pcFileName, strerror( iErrorNo ) ) );
+
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "521-\"%s\" %s;\r\n"
+ "521 taking no action\r\n",
+ pxClient->pcFileName, errMsg );
+
+ xResult = pdFALSE;
+ }
+
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+/*
+ #### # #####
+# # # # # #
+# # # # #
+# ### ###### #### # # #### ###### ####
+ ## # # # # # # # # # # #
+ ## # # ###### # # ##### # ######
+# # # # # # # # # # #
+# # # # # ## # # # # # ## # ##
+ #### ##### ###### #### ##### ### ## ## ####
+*/
+static BaseType_t prvSizeDateFile( FTPClient_t *pxClient, char *pcFileName, BaseType_t xSendDate )
+{
+BaseType_t xResult = pdFALSE;
+char *pcPtr;
+
+ /* SIZE: get the size of a file (xSendDate = 0)
+ MDTM: get data and time properties (xSendDate = 1) */
+ xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName );
+
+ pcPtr = strrchr( pxClient->pcFileName, '/' );
+
+ if( ( pcPtr != NULL ) && ( pcPtr[ 1 ] != '\0' ) )
+ {
+ FF_Stat_t xStatBuf;
+ int32_t iRc = ff_stat( pxClient->pcFileName, &xStatBuf );
+ if (iRc < 0 )
+ FreeRTOS_printf( ("In %s: %s\n", pxClient->pcFileName,
+ ( const char* )strerror( stdioGET_ERRNO() ) ) );
+
+ if( iRc == 0 )
+ {
+ BaseType_t xLength;
+ /* "YYYYMMDDhhmmss" */
+ if( xSendDate != pdFALSE )
+ {
+ #if( ffconfigTIME_SUPPORT != 0 )
+ {
+ FF_TimeStruct_t tmStruct;
+ time_t secs = xStatBuf.st_mtime;
+ FreeRTOS_gmtime_r( &secs, &tmStruct );
+
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %04u%02u%02u%02u%02u%02u\r\n",
+ tmStruct.tm_year + 1900,
+ tmStruct.tm_mon+1,
+ tmStruct.tm_mday,
+ tmStruct.tm_hour,
+ tmStruct.tm_min,
+ tmStruct.tm_sec );
+ }
+ #else
+ {
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 19700101000000\r\n",
+ }
+ #endif
+ }
+ else
+ {
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %lu\r\n", xStatBuf.st_size );
+ }
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+ xResult = pdTRUE;
+ }
+ else
+ {
+ FreeRTOS_printf( ("ftp::sizeDateFile: No such file %s\n", pxClient->pcFileName ) );
+ }
+ } else {
+ FreeRTOS_printf( ("ftp::sizeDateFile: Invalid file name: %s ?\n", pxClient->pcFileName ) );
+ }
+ if( xResult == pdFALSE )
+ {
+ prvSendReply( pxClient->xSocket, REPL_450, 0 ); /* "Requested file action not taken". */
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+/*
+## ## ## ## ##### ###### ## ## #####
+### ### # # # # # # ### ### # #
+# ### # # # # # # # # ### # # #
+# # # # # # # # # # # # # #
+# # # #### # # ###### # # # # #
+# # # # # # # ## # # # #
+# # # # # # # # # # # #
+# # # # # # # # # # # #
+# # ### ## ##### ### ## # # #####
+*/
+static BaseType_t prvMakeRemoveDir( FTPClient_t *pxClient, const char *pcDirectory, BaseType_t xDoRemove )
+{
+BaseType_t xResult;
+BaseType_t xLength;
+int32_t iRc;
+int iErrorNo;
+
+ /* MKD: Make / create a directory (xDoRemove = 0)
+ RMD: Remove a directory (xDoRemove = 1) */
+ xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcDirectory );
+
+ if( xDoRemove )
+ {
+ iRc = ff_rmdir( pxClient->pcFileName );
+ }
+ else
+ {
+ #if( ffconfigMKDIR_RECURSIVE != 0 )
+ {
+ iRc = ff_mkdir( pxClient->pcFileName, pdFALSE );
+ }
+ #else
+ {
+ iRc = ff_mkdir( pxClient->pcFileName );
+ }
+ #endif /* ffconfigMKDIR_RECURSIVE */
+ }
+ xResult = pdTRUE;
+
+ if( iRc >= 0 )
+ {
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "257 \"%s\" directory %s\r\n",
+ pxClient->pcFileName, xDoRemove ? "removed" : "created" );
+ }
+ else
+ {
+ const char *errMsg = "other error";
+ BaseType_t xFTPCode = 521;
+
+ xResult = pdFALSE;
+ iErrorNo = stdioGET_ERRNO();
+ switch( iErrorNo )
+ {
+ case pdFREERTOS_ERRNO_EEXIST: errMsg = "Directory already exists"; break;
+ case pdFREERTOS_ERRNO_ENOTDIR: errMsg = "Invalid path"; break; /* -34 The path of the file was not found. *//*_RB_ As before, what do these negative numbers relate to? */
+ case pdFREERTOS_ERRNO_ENOTEMPTY:errMsg = "Dir not empty"; break;
+ case pdFREERTOS_ERRNO_EROFS: errMsg = "Read-only"; break; /* -33 Tried to FF_Open() a file marked read only. */
+ default: errMsg = strerror( iErrorNo ); break;
+ }
+ if( iErrorNo == pdFREERTOS_ERRNO_ENOSPC )
+ {
+ xFTPCode = 552;
+ }
+ xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ),
+ "%ld-\"%s\" %s;\r\n"
+ "%ld taking no action\r\n",
+ xFTPCode, pxClient->pcFileName, errMsg, xFTPCode );
+ FreeRTOS_printf( ( "%sdir '%s': %s\n", xDoRemove ? "rm" : "mk", pxClient->pcFileName, errMsg ) );
+ }
+ prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength );
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+static portINLINE BaseType_t IsDigit( char cChar )
+{
+BaseType_t xResult;
+
+ if( cChar >= '0' && cChar <= '9' )
+ {
+ xResult = pdTRUE;
+ }
+ else
+ {
+ xResult = pdFALSE;
+ }
+ return xResult;
+}
+
+static BaseType_t prvSendReply( Socket_t xSocket, const char *pcBuffer, BaseType_t xLength )
+{
+BaseType_t xResult;
+
+ if( xLength == 0 )
+ {
+ xLength = strlen( pcBuffer );
+ }
+ xResult = FreeRTOS_send( xSocket, ( const void * )pcBuffer, ( size_t ) xLength, 0 );
+ if( IsDigit( ( int ) pcBuffer[ 0 ] ) &&
+ IsDigit( ( int ) pcBuffer[ 1 ] ) &&
+ IsDigit( ( int ) pcBuffer[ 2 ] ) &&
+ IsDigit( ( int ) pcBuffer[ 3 ] ) )
+ {
+ const char *last = pcBuffer + strlen( pcBuffer );
+ int iLength;
+ while( ( last > pcBuffer ) && ( ( last[ -1 ] == ftpASCII_CR ) || ( last[ -1 ] == ftpASCII_LF ) ) )
+ {
+ last--;
+ }
+ iLength = ( int )( last - pcBuffer );
+ FF_PRINTF( " %-*.*s", iLength, iLength, pcBuffer );
+ }
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 )
+
+ /*
+ * The following function is called for every file received:
+ * void vApplicationFTPReceivedHook( pcFileName, ulSize, pxFTPClient );
+ * This callback function may do a callback to vFTPReplyMessage() to send messages
+ * to the FTP client like:
+ * 200-Please wait: Received new firmware
+ * 200-Please wait: Please wait a few seconds for reboot
+ */
+ void vFTPReplyMessage( struct xFTP_CLIENT *pxFTPClient, const char *pcMessage )
+ {
+ if( ( pxFTPClient != NULL ) && ( pxFTPClient->xSocket != NULL ) )
+ {
+ prvSendReply( pxFTPClient->xSocket, pcMessage, 0 );
+ }
+ }
+ /*-----------------------------------------------------------*/
+
+#endif /* ipconfigFTP_HAS_RECEIVED_HOOK != 0 */
+
+/*
+ * Some explanation:
+ * The FTP client may send: "DELE readme.txt"
+ * Here the complete path is constructed consisting of 3 parts:
+ *
+ * pxClient->pcRootDir + pxClient->pcCurrentDir + pcFileName
+ *
+ * 'pcCurrentDir' will not be applied for an absolute path like in "DELE /.htaccess"
+ */
+BaseType_t xMakeAbsolute( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName )
+{
+BaseType_t xLength = strlen( pxClient->pcRootDir );
+
+ if( pcFileName[ 0 ] != '/' )
+ {
+ char *pcNewDirBuffer = pcNEW_DIR;
+ BaseType_t xCurLength;
+
+ xCurLength = strlen( pxClient->pcCurrentDir );
+ if( pcBuffer == pcNEW_DIR )
+ {
+ /* In one call, the result already goes into pcNEW_DIR.
+ Use pcFILE_BUFFER in that case */
+ pcNewDirBuffer = pcFILE_BUFFER;
+ }
+ snprintf( pcNewDirBuffer, sizeof( pcNEW_DIR ), "%s%s%s",
+ pxClient->pcCurrentDir,
+ pxClient->pcCurrentDir[ xCurLength - 1 ] == '/' ? "" : "/",
+ pcFileName );
+ pcFileName = pcNewDirBuffer;
+ }
+ if( strncasecmp( pxClient->pcRootDir, pcFileName, xLength ) == 0 )
+ {
+ xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName );
+ }
+ else
+ {
+ xLength = snprintf( pcBuffer, xBufferLength, "%s/%s",
+ pxClient->pcRootDir,
+ pcFileName[ 0 ] == '/' ? ( pcFileName + 1 ) : pcFileName );
+ }
+
+ #if( ipconfigFTP_FS_USES_BACKSLAH == 1 )
+ for( pcPtr = pcBuffer; *pcPtr; pcPtr++ )
+ {
+ if( pcPtr[ 0 ] == '/' )
+ {
+ pcPtr[ 0 ] = '\\';
+ }
+ }
+ #endif
+
+ return xLength;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xMakeRelative( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName )
+{
+BaseType_t xLength = strlen( pxClient->pcRootDir );
+
+ if( strncasecmp ( pxClient->pcRootDir, pcFileName, xLength ) == 0 )
+ {
+ xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName + xLength );
+ }
+ else
+ {
+ xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName );
+ }
+
+ return xLength;
+}
+/*-----------------------------------------------------------*/
+
+#endif /* ipconfigUSE_FTP */
+
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_commands.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_commands.c
new file mode 100644
index 000000000..cb9462c89
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_commands.c
@@ -0,0 +1,103 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+
+/* Standard includes. */
+#include <stdio.h>
+#include <stdlib.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+
+#include "FreeRTOS_HTTP_commands.h"
+
+const struct xWEB_COMMAND xWebCommands[ WEB_CMD_COUNT ] =
+{
+ { 3, "GET", ECMD_GET },
+ { 4, "HEAD", ECMD_HEAD },
+ { 4, "POST", ECMD_POST },
+ { 3, "PUT", ECMD_PUT },
+ { 6, "DELETE", ECMD_DELETE },
+ { 5, "TRACE", ECMD_TRACE },
+ { 7, "OPTIONS", ECMD_OPTIONS },
+ { 7, "CONNECT", ECMD_CONNECT },
+ { 5, "PATCH", ECMD_PATCH },
+ { 4, "UNKN", ECMD_UNK },
+};
+
+const char *webCodename (int aCode)
+{
+ switch (aCode) {
+ case WEB_REPLY_OK: // = 200,
+ return "OK";
+ case WEB_NO_CONTENT: // 204
+ return "No content";
+ case WEB_BAD_REQUEST: // = 400,
+ return "Bad request";
+ case WEB_UNAUTHORIZED: // = 401,
+ return "Authorization Required";
+ case WEB_NOT_FOUND: // = 404,
+ return "Not Found";
+ case WEB_GONE: // = 410,
+ return "Done";
+ case WEB_PRECONDITION_FAILED: // = 412,
+ return "Precondition Failed";
+ case WEB_INTERNAL_SERVER_ERROR: // = 500,
+ return "Internal Server Error";
+ }
+ return "Unknown";
+}
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_server.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_server.c
new file mode 100644
index 000000000..1581f62f2
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_server.c
@@ -0,0 +1,455 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/* Standard includes. */
+#include <stdio.h>
+#include <stdlib.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+
+/* FreeRTOS Protocol includes. */
+#include "FreeRTOS_HTTP_commands.h"
+#include "FreeRTOS_TCP_server.h"
+#include "FreeRTOS_server_private.h"
+
+/* FreeRTOS+FAT includes. */
+#include "ff_stdio.h"
+
+#ifndef HTTP_SERVER_BACKLOG
+ #define HTTP_SERVER_BACKLOG ( 12 )
+#endif
+
+#ifndef USE_HTML_CHUNKS
+ #define USE_HTML_CHUNKS ( 0 )
+#endif
+
+#if !defined( ARRAY_SIZE )
+ #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] )
+#endif
+
+/* Some defines to make the code more readbale */
+#define pcCOMMAND_BUFFER pxClient->pxParent->pcCommandBuffer
+#define pcNEW_DIR pxClient->pxParent->pcNewDir
+#define pcFILE_BUFFER pxClient->pxParent->pcFileBuffer
+
+#ifndef ipconfigHTTP_REQUEST_CHARACTER
+ #define ipconfigHTTP_REQUEST_CHARACTER '?'
+#endif
+
+/*_RB_ Need comment block, although fairly self evident. */
+static void prvFileClose( HTTPClient_t *pxClient );
+static BaseType_t prvProcessCmd( HTTPClient_t *pxClient, BaseType_t xIndex );
+static const char *pcGetContentsType( const char *apFname );
+static BaseType_t prvOpenURL( HTTPClient_t *pxClient );
+static BaseType_t prvSendFile( HTTPClient_t *pxClient );
+static BaseType_t prvSendReply( HTTPClient_t *pxClient, BaseType_t xCode );
+
+static const char pcEmptyString[1] = { '\0' };
+
+typedef struct xTYPE_COUPLE
+{
+ const char *pcExtension;
+ const char *pcType;
+} TypeCouple_t;
+
+static TypeCouple_t pxTypeCouples[ ] =
+{
+ { "html", "text/html" },
+ { "css", "text/css" },
+ { "js", "text/javascript" },
+ { "png", "image/png" },
+ { "jpg", "image/jpeg" },
+ { "gif", "image/gif" },
+ { "txt", "text/plain" },
+ { "mp3", "audio/mpeg3" },
+ { "wav", "audio/wav" },
+ { "flac", "audio/ogg" },
+ { "pdf", "application/pdf" },
+ { "ttf", "application/x-font-ttf" },
+ { "ttc", "application/x-font-ttf" }
+};
+
+void vHTTPClientDelete( TCPClient_t *pxTCPClient )
+{
+HTTPClient_t *pxClient = ( HTTPClient_t * ) pxTCPClient;
+
+ /* This HTTP client stops, close / release all resources. */
+ if( pxClient->xSocket != FREERTOS_NO_SOCKET )
+ {
+ FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL );
+ FreeRTOS_closesocket( pxClient->xSocket );
+ pxClient->xSocket = FREERTOS_NO_SOCKET;
+ }
+ prvFileClose( pxClient );
+}
+/*-----------------------------------------------------------*/
+
+static void prvFileClose( HTTPClient_t *pxClient )
+{
+ if( pxClient->pxFileHandle != NULL )
+ {
+ FreeRTOS_printf( ( "Closing file: %s\n", pxClient->pcCurrentFilename ) );
+ ff_fclose( pxClient->pxFileHandle );
+ pxClient->pxFileHandle = NULL;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvSendReply( HTTPClient_t *pxClient, BaseType_t xCode )
+{
+struct xTCP_SERVER *pxParent = pxClient->pxParent;
+BaseType_t xRc;
+
+ /* A normal command reply on the main socket (port 21). */
+ char *pcBuffer = pxParent->pcFileBuffer;
+
+ xRc = snprintf( pcBuffer, sizeof( pxParent->pcFileBuffer ),
+ "HTTP/1.1 %d %s\r\n"
+#if USE_HTML_CHUNKS
+ "Transfer-Encoding: chunked\r\n"
+#endif
+ "Content-Type: %s\r\n"
+ "Connection: keep-alive\r\n"
+ "%s\r\n",
+ ( int ) xCode,
+ webCodename (xCode),
+ pxParent->pcContentsType[0] ? pxParent->pcContentsType : "text/html",
+ pxParent->pcExtraContents );
+
+ pxParent->pcContentsType[0] = '\0';
+ pxParent->pcExtraContents[0] = '\0';
+
+ xRc = FreeRTOS_send( pxClient->xSocket, ( const void * ) pcBuffer, xRc, 0 );
+ pxClient->bits.bReplySent = pdTRUE_UNSIGNED;
+
+ return xRc;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvSendFile( HTTPClient_t *pxClient )
+{
+size_t uxSpace;
+size_t uxCount;
+BaseType_t xRc = 0;
+
+ if( pxClient->bits.bReplySent == pdFALSE_UNSIGNED )
+ {
+ pxClient->bits.bReplySent = pdTRUE_UNSIGNED;
+
+ strcpy( pxClient->pxParent->pcContentsType, pcGetContentsType( pxClient->pcCurrentFilename ) );
+ snprintf( pxClient->pxParent->pcExtraContents, sizeof( pxClient->pxParent->pcExtraContents ),
+ "Content-Length: %d\r\n", ( int ) pxClient->uxBytesLeft );
+
+ /* "Requested file action OK". */
+ xRc = prvSendReply( pxClient, WEB_REPLY_OK );
+ }
+
+ if( xRc >= 0 ) do
+ {
+ uxSpace = FreeRTOS_tx_space( pxClient->xSocket );
+
+ if( pxClient->uxBytesLeft < uxSpace )
+ {
+ uxCount = pxClient->uxBytesLeft;
+ }
+ else
+ {
+ uxCount = uxSpace;
+ }
+
+ if( uxCount > 0u )
+ {
+ if( uxCount > sizeof( pxClient->pxParent->pcFileBuffer ) )
+ {
+ uxCount = sizeof( pxClient->pxParent->pcFileBuffer );
+ }
+ ff_fread( pxClient->pxParent->pcFileBuffer, 1, uxCount, pxClient->pxFileHandle );
+ pxClient->uxBytesLeft -= uxCount;
+
+ xRc = FreeRTOS_send( pxClient->xSocket, pxClient->pxParent->pcFileBuffer, uxCount, 0 );
+ if( xRc < 0 )
+ {
+ break;
+ }
+ }
+ } while( uxCount > 0u );
+
+ if( pxClient->uxBytesLeft == 0u )
+ {
+ /* Writing is ready, no need for further 'eSELECT_WRITE' events. */
+ FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE );
+ prvFileClose( pxClient );
+ }
+ else
+ {
+ /* Wake up the TCP task as soon as this socket may be written to. */
+ FreeRTOS_FD_SET( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE );
+ }
+
+ return xRc;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvOpenURL( HTTPClient_t *pxClient )
+{
+BaseType_t xRc;
+char pcSlash[ 2 ];
+
+ pxClient->bits.ulFlags = 0;
+
+ #if( ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK != 0 )
+ {
+ if( strchr( pxClient->pcUrlData, ipconfigHTTP_REQUEST_CHARACTER ) != NULL )
+ {
+ size_t xResult;
+
+ xResult = uxApplicationHTTPHandleRequestHook( pxClient->pcUrlData, pxClient->pcCurrentFilename, sizeof( pxClient->pcCurrentFilename ) );
+ if( xResult > 0 )
+ {
+ strcpy( pxClient->pxParent->pcContentsType, "text/html" );
+ snprintf( pxClient->pxParent->pcExtraContents, sizeof( pxClient->pxParent->pcExtraContents ),
+ "Content-Length: %d\r\n", ( int ) xResult );
+ xRc = prvSendReply( pxClient, WEB_REPLY_OK ); /* "Requested file action OK" */
+ if( xRc > 0 )
+ {
+ xRc = FreeRTOS_send( pxClient->xSocket, pxClient->pcCurrentFilename, xResult, 0 );
+ }
+ /* Although against the coding standard of FreeRTOS, a return is
+ done here to simplify this conditional code. */
+ return xRc;
+ }
+ }
+ }
+ #endif /* ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK */
+
+ if( pxClient->pcUrlData[ 0 ] != '/' )
+ {
+ /* Insert a slash before the file name. */
+ pcSlash[ 0 ] = '/';
+ pcSlash[ 1 ] = '\0';
+ }
+ else
+ {
+ /* The browser provided a starting '/' already. */
+ pcSlash[ 0 ] = '\0';
+ }
+ snprintf( pxClient->pcCurrentFilename, sizeof( pxClient->pcCurrentFilename ), "%s%s%s",
+ pxClient->pcRootDir,
+ pcSlash,
+ pxClient->pcUrlData);
+
+ pxClient->pxFileHandle = ff_fopen( pxClient->pcCurrentFilename, "rb" );
+
+ FreeRTOS_printf( ( "Open file '%s': %s\n", pxClient->pcCurrentFilename,
+ pxClient->pxFileHandle != NULL ? "Ok" : strerror( stdioGET_ERRNO() ) ) );
+
+ if( pxClient->pxFileHandle == NULL )
+ {
+ /* "404 File not found". */
+ xRc = prvSendReply( pxClient, WEB_NOT_FOUND );
+ }
+ else
+ {
+ pxClient->uxBytesLeft = ( size_t ) pxClient->pxFileHandle->ulFileSize;
+ xRc = prvSendFile( pxClient );
+ }
+
+ return xRc;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvProcessCmd( HTTPClient_t *pxClient, BaseType_t xIndex )
+{
+BaseType_t xResult = 0;
+
+ /* A new command has been received. Process it. */
+ switch( xIndex )
+ {
+ case ECMD_GET:
+ xResult = prvOpenURL( pxClient );
+ break;
+
+ case ECMD_HEAD:
+ case ECMD_POST:
+ case ECMD_PUT:
+ case ECMD_DELETE:
+ case ECMD_TRACE:
+ case ECMD_OPTIONS:
+ case ECMD_CONNECT:
+ case ECMD_PATCH:
+ case ECMD_UNK:
+ {
+ FreeRTOS_printf( ( "prvProcessCmd: Not implemented: %s\n",
+ xWebCommands[xIndex].pcCommandName ) );
+ }
+ break;
+ }
+
+ return xResult;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xHTTPClientWork( TCPClient_t *pxTCPClient )
+{
+BaseType_t xRc;
+HTTPClient_t *pxClient = ( HTTPClient_t * ) pxTCPClient;
+
+ if( pxClient->pxFileHandle != NULL )
+ {
+ prvSendFile( pxClient );
+ }
+
+ xRc = FreeRTOS_recv( pxClient->xSocket, ( void * )pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), 0 );
+
+ if( xRc > 0 )
+ {
+ BaseType_t xIndex;
+ const char *pcEndOfCmd;
+ const struct xWEB_COMMAND *curCmd;
+ char *pcBuffer = pcCOMMAND_BUFFER;
+
+ if( xRc < ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) )
+ {
+ pcBuffer[ xRc ] = '\0';
+ }
+ while( xRc && ( pcBuffer[ xRc - 1 ] == 13 || pcBuffer[ xRc - 1 ] == 10 ) )
+ {
+ pcBuffer[ --xRc ] = '\0';
+ }
+ pcEndOfCmd = pcBuffer + xRc;
+
+ curCmd = xWebCommands;
+
+ /* Pointing to "/index.html HTTP/1.1". */
+ pxClient->pcUrlData = pcBuffer;
+
+ /* Pointing to "HTTP/1.1". */
+ pxClient->pcRestData = pcEmptyString;
+
+ /* Last entry is "ECMD_UNK". */
+ for( xIndex = 0; xIndex < WEB_CMD_COUNT - 1; xIndex++, curCmd++ )
+ {
+ BaseType_t xLength;
+
+ xLength = curCmd->xCommandLength;
+ if( ( xRc >= xLength ) && ( memcmp( curCmd->pcCommandName, pcBuffer, xLength ) == 0 ) )
+ {
+ char *pcLastPtr;
+
+ pxClient->pcUrlData += xLength + 1;
+ for( pcLastPtr = (char *)pxClient->pcUrlData; pcLastPtr < pcEndOfCmd; pcLastPtr++ )
+ {
+ char ch = *pcLastPtr;
+ if( ( ch == '\0' ) || ( strchr( "\n\r \t", ch ) != NULL ) )
+ {
+ *pcLastPtr = '\0';
+ pxClient->pcRestData = pcLastPtr + 1;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if( xIndex < ( WEB_CMD_COUNT - 1 ) )
+ {
+ xRc = prvProcessCmd( pxClient, xIndex );
+ }
+ }
+ else if( xRc < 0 )
+ {
+ /* The connection will be closed and the client will be deleted. */
+ FreeRTOS_printf( ( "xHTTPClientWork: rc = %ld\n", xRc ) );
+ }
+ return xRc;
+}
+/*-----------------------------------------------------------*/
+
+static const char *pcGetContentsType (const char *apFname)
+{
+ const char *slash = NULL;
+ const char *dot = NULL;
+ const char *ptr;
+ const char *pcResult = "text/html";
+ BaseType_t x;
+
+ for( ptr = apFname; *ptr; ptr++ )
+ {
+ if (*ptr == '.') dot = ptr;
+ if (*ptr == '/') slash = ptr;
+ }
+ if( dot > slash )
+ {
+ dot++;
+ for( x = 0; x < ARRAY_SIZE( pxTypeCouples ); x++ )
+ {
+ if( strcasecmp( dot, pxTypeCouples[ x ].pcExtension ) == 0 )
+ {
+ pcResult = pxTypeCouples[ x ].pcType;
+ break;
+ }
+ }
+ }
+ return pcResult;
+}
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/NTP/NTPDemo.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/NTP/NTPDemo.c
new file mode 100644
index 000000000..fb3861f4b
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/NTP/NTPDemo.c
@@ -0,0 +1,472 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*
+ * NTPDemo.c
+ *
+ * An example of how to lookup a domain using DNS
+ * And also how to send and receive UDP messages to get the NTP time
+ *
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_DNS.h"
+#include "FreeRTOS_Stream_Buffer.h"
+
+/* Use the date & time functions from +FAT. */
+#include "ff_time.h"
+
+#include "NTPDemo.h"
+#include "ntpClient.h"
+
+#include "date_and_time.h"
+
+enum EStatus {
+ EStatusLookup,
+ EStatusAsking,
+ EStatusPause,
+ EStatusFailed,
+};
+
+static struct SNtpPacket xNTPPacket;
+
+#if( ipconfigUSE_CALLBACKS == 0 )
+ static char cRecvBuffer[ sizeof( struct SNtpPacket ) + 64 ];
+#endif
+
+static enum EStatus xStatus = EStatusLookup;
+
+static const char *pcTimeServers[] = {
+ "0.asia.pool.ntp.org",
+ "0.europe.pool.ntp.org",
+ "0.id.pool.ntp.org",
+ "0.south-america.pool.ntp.org",
+ "0.oceania.pool.ntp.org",
+ "0.north-america.pool.ntp.org"
+};
+
+static SemaphoreHandle_t xNTPWakeupSem = NULL;
+static uint32_t ulIPAddressFound;
+static Socket_t xUDPSocket = NULL;
+static TaskHandle_t xNTPTaskhandle = NULL;
+static TickType_t uxSendTime;
+
+static void prvNTPTask( void *pvParameters );
+
+static void vSignalTask( void )
+{
+ #if( ipconfigUSE_CALLBACKS == 0 )
+ if( xUDPSocket != NULL )
+ {
+ /* Send a signal to the socket so that the
+ FreeRTOS_recvfrom will get interrupted. */
+ FreeRTOS_SignalSocket( xUDPSocket );
+ }
+ else
+ #endif
+ if( xNTPWakeupSem != NULL )
+ {
+ xSemaphoreGive( xNTPWakeupSem );
+ }
+}
+
+void vStartNTPTask( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority )
+{
+ /* The only public function in this module: start a task to contact
+ some NTP server. */
+
+ if( xNTPTaskhandle != NULL )
+ {
+ switch( xStatus )
+ {
+ case EStatusPause:
+ xStatus = EStatusAsking;
+ vSignalTask();
+ break;
+ case EStatusLookup:
+ FreeRTOS_printf( ( "NTP looking up server\n" ) );
+ break;
+ case EStatusAsking:
+ FreeRTOS_printf( ( "NTP still asking\n" ) );
+ break;
+ case EStatusFailed:
+ FreeRTOS_printf( ( "NTP failed somehow\n" ) );
+ ulIPAddressFound = 0ul;
+ xStatus = EStatusLookup;
+ vSignalTask();
+ break;
+ }
+ }
+ else
+ {
+ xUDPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
+ if( xUDPSocket != NULL )
+ {
+ struct freertos_sockaddr xAddress;
+ #if( ipconfigUSE_CALLBACKS != 0 )
+ BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 0 );
+ #else
+ BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 );
+ #endif
+
+ xAddress.sin_addr = 0ul;
+ xAddress.sin_port = FreeRTOS_htons( NTP_PORT );
+
+ FreeRTOS_bind( xUDPSocket, &xAddress, sizeof( xAddress ) );
+ FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
+ xTaskCreate( prvNTPTask, /* The function that implements the task. */
+ ( const char * ) "NTP client", /* Just a text name for the task to aid debugging. */
+ usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */
+ NULL, /* The task parameter, not used in this case. */
+ uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */
+ &xNTPTaskhandle ); /* The task handle. */
+ }
+ else
+ {
+ FreeRTOS_printf( ( "Creating socket failed\n" ) );
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void vDNS_callback( const char *pcName, void *pvSearchID, uint32_t ulIPAddress )
+{
+char pcBuf[16];
+
+ /* The DNS lookup has a result, or it has reached the time-out. */
+ FreeRTOS_inet_ntoa( ulIPAddress, pcBuf );
+ FreeRTOS_printf( ( "IP address of %s found: %s\n", pcName, pcBuf ) );
+ if( ulIPAddressFound == 0ul )
+ {
+ ulIPAddressFound = ulIPAddress;
+ }
+ /* For testing: in case DNS doen't respond, still try some NTP server
+ with a known IP-address. */
+ if( ulIPAddressFound == 0ul )
+ {
+ ulIPAddressFound = FreeRTOS_inet_addr_quick( 184, 105, 182, 7 );
+/* ulIPAddressFound = FreeRTOS_inet_addr_quick( 103, 242, 70, 4 ); */
+ }
+ xStatus = EStatusAsking;
+
+ vSignalTask();
+}
+/*-----------------------------------------------------------*/
+
+static void prvSwapFields( struct SNtpPacket *pxPacket)
+{
+ /* NTP messages are big-endian */
+ pxPacket->rootDelay = FreeRTOS_htonl( pxPacket->rootDelay );
+ pxPacket->rootDispersion = FreeRTOS_htonl( pxPacket->rootDispersion );
+
+ pxPacket->referenceTimestamp.seconds = FreeRTOS_htonl( pxPacket->referenceTimestamp.seconds );
+ pxPacket->referenceTimestamp.fraction = FreeRTOS_htonl( pxPacket->referenceTimestamp.fraction );
+
+ pxPacket->originateTimestamp.seconds = FreeRTOS_htonl( pxPacket->originateTimestamp.seconds );
+ pxPacket->originateTimestamp.fraction = FreeRTOS_htonl( pxPacket->originateTimestamp.fraction );
+
+ pxPacket->receiveTimestamp.seconds = FreeRTOS_htonl( pxPacket->receiveTimestamp.seconds );
+ pxPacket->receiveTimestamp.fraction = FreeRTOS_htonl( pxPacket->receiveTimestamp.fraction );
+
+ pxPacket->transmitTimestamp.seconds = FreeRTOS_htonl( pxPacket->transmitTimestamp.seconds );
+ pxPacket->transmitTimestamp.fraction = FreeRTOS_htonl( pxPacket->transmitTimestamp.fraction );
+}
+/*-----------------------------------------------------------*/
+
+static void prvNTPPacketInit( )
+{
+ memset (&xNTPPacket, '\0', sizeof( xNTPPacket ) );
+
+ xNTPPacket.flags = 0xDB; /* value 0xDB : mode 3 (client), version 3, leap indicator unknown 3 */
+ xNTPPacket.poll = 10; /* 10 means 1 << 10 = 1024 seconds */
+ xNTPPacket.precision = 0xFA; /* = 250 = 0.015625 seconds */
+ xNTPPacket.rootDelay = 0x5D2E; /* 0x5D2E = 23854 or (23854/65535)= 0.3640 sec */
+ xNTPPacket.rootDispersion = 0x0008CAC8; /* 0x0008CAC8 = 8.7912 seconds */
+
+ /* use the recorded NTP time */
+ time_t uxSecs = FreeRTOS_time( NULL );/* apTime may be NULL, returns seconds */
+
+ xNTPPacket.referenceTimestamp.seconds = uxSecs; /* Current time */
+ xNTPPacket.transmitTimestamp.seconds = uxSecs + 3;
+
+ /* Transform the contents of the fields from native to big endian. */
+ prvSwapFields( &xNTPPacket );
+}
+/*-----------------------------------------------------------*/
+
+static void prvReadTime( struct SNtpPacket * pxPacket )
+{
+ FF_TimeStruct_t xTimeStruct;
+ time_t uxPreviousSeconds;
+ time_t uxPreviousMS;
+
+ time_t uxCurrentSeconds;
+ time_t uxCurrentMS;
+
+ const char *pcTimeUnit;
+ int32_t ilDiff;
+ TickType_t uxTravelTime;
+
+ uxTravelTime = xTaskGetTickCount() - uxSendTime;
+
+ /* Transform the contents of the fields from big to native endian. */
+ prvSwapFields( pxPacket );
+
+ uxCurrentSeconds = pxPacket->receiveTimestamp.seconds - TIME1970;
+ uxCurrentMS = pxPacket->receiveTimestamp.fraction / 4294967;
+ uxCurrentSeconds += uxCurrentMS / 1000;
+ uxCurrentMS = uxCurrentMS % 1000;
+
+ // Get the last time recorded
+ uxPreviousSeconds = FreeRTOS_get_secs_msec( &uxPreviousMS );
+
+ // Set the new time with precision in msec. */
+ FreeRTOS_set_secs_msec( &uxCurrentSeconds, &uxCurrentMS );
+
+ if( uxCurrentSeconds >= uxPreviousSeconds )
+ {
+ ilDiff = ( int32_t ) ( uxCurrentSeconds - uxPreviousSeconds );
+ }
+ else
+ {
+ ilDiff = 0 - ( int32_t ) ( uxPreviousSeconds - uxCurrentSeconds );
+ }
+
+ if( ( ilDiff < -5 ) || ( ilDiff > 5 ) )
+ {
+ /* More than 5 seconds difference. */
+ pcTimeUnit = "sec";
+ }
+ else
+ {
+ /* Less than or equal to 5 second difference. */
+ pcTimeUnit = "ms";
+ uint32_t ulLowest = ( uxCurrentSeconds <= uxPreviousSeconds ) ? uxCurrentSeconds : uxPreviousSeconds;
+ int32_t iCurMS = 1000 * ( uxCurrentSeconds - ulLowest ) + uxCurrentMS;
+ int32_t iPrevMS = 1000 * ( uxPreviousSeconds - ulLowest ) + uxPreviousMS;
+ ilDiff = iCurMS - iPrevMS;
+ }
+ uxCurrentSeconds -= iTimeZone;
+
+ FreeRTOS_gmtime_r( &uxCurrentSeconds, &xTimeStruct );
+
+ /*
+ 378.067 [NTP client] NTP time: 9/11/2015 16:11:19.559 Diff -20 ms (289 ms)
+ 379.441 [NTP client] NTP time: 9/11/2015 16:11:20.933 Diff 0 ms (263 ms)
+ */
+
+ FreeRTOS_printf( ("NTP time: %d/%d/%02d %2d:%02d:%02d.%03u Diff %d %s (%lu ms)\n",
+ xTimeStruct.tm_mday,
+ xTimeStruct.tm_mon + 1,
+ xTimeStruct.tm_year + 1900,
+ xTimeStruct.tm_hour,
+ xTimeStruct.tm_min,
+ xTimeStruct.tm_sec,
+ ( unsigned )uxCurrentMS,
+ ( unsigned )ilDiff,
+ pcTimeUnit,
+ uxTravelTime ) );
+
+ /* Remove compiler warnings in case FreeRTOS_printf() is not used. */
+ ( void ) pcTimeUnit;
+ ( void ) uxTravelTime;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_CALLBACKS != 0 )
+
+ static BaseType_t xOnUDPReceive( Socket_t xSocket, void * pvData, size_t xLength,
+ const struct freertos_sockaddr *pxFrom, const struct freertos_sockaddr *pxDest )
+ {
+ if( xLength >= sizeof( xNTPPacket ) )
+ {
+ prvReadTime( ( struct SNtpPacket *)pvData );
+ if( xStatus != EStatusPause )
+ {
+ xStatus = EStatusPause;
+ }
+ }
+ vSignalTask();
+ /* Tell the driver not to store the RX data */
+ return 1;
+ }
+ /*-----------------------------------------------------------*/
+
+#endif /* ipconfigUSE_CALLBACKS != 0 */
+
+static void prvNTPTask( void *pvParameters )
+{
+BaseType_t xServerIndex = 3;
+struct freertos_sockaddr xAddress;
+#if( ipconfigUSE_CALLBACKS != 0 )
+ F_TCP_UDP_Handler_t xHandler;
+#endif /* ipconfigUSE_CALLBACKS != 0 */
+
+ xStatus = EStatusLookup;
+ #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) || ( ipconfigUSE_CALLBACKS != 0 )
+ {
+ xNTPWakeupSem = xSemaphoreCreateBinary();
+ }
+ #endif
+
+ #if( ipconfigUSE_CALLBACKS != 0 )
+ {
+ memset( &xHandler, '\0', sizeof( xHandler ) );
+ xHandler.pxOnUDPReceive = xOnUDPReceive;
+ FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_UDP_RECV_HANDLER, ( void * ) &xHandler, sizeof( xHandler ) );
+ }
+ #endif
+ #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 )
+ {
+ FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_SET_SEMAPHORE, ( void * ) &xNTPWakeupSem, sizeof( xNTPWakeupSem ) );
+ }
+ #endif
+ for( ; ; )
+ {
+ switch( xStatus )
+ {
+ case EStatusLookup:
+ if( ( ulIPAddressFound == 0ul ) || ( ulIPAddressFound == ~0ul ) )
+ {
+ if( ++xServerIndex == sizeof( pcTimeServers ) / sizeof( pcTimeServers[ 0 ] ) )
+ {
+ xServerIndex = 0;
+ }
+ FreeRTOS_printf( ( "Looking up server '%s'\n", pcTimeServers[ xServerIndex ] ) );
+ FreeRTOS_gethostbyname_a( pcTimeServers[ xServerIndex ], vDNS_callback, (void *)NULL, 1200 );
+ }
+ else
+ {
+ xStatus = EStatusAsking;
+ }
+ break;
+
+ case EStatusAsking:
+ {
+ char pcBuf[16];
+
+ prvNTPPacketInit( );
+ xAddress.sin_addr = ulIPAddressFound;
+ xAddress.sin_port = FreeRTOS_htons( NTP_PORT );
+
+ FreeRTOS_inet_ntoa( xAddress.sin_addr, pcBuf );
+ FreeRTOS_printf( ( "Sending UDP message to %s:%u\n",
+ pcBuf,
+ FreeRTOS_ntohs( xAddress.sin_port ) ) );
+
+ uxSendTime = xTaskGetTickCount( );
+ FreeRTOS_sendto( xUDPSocket, ( void * )&xNTPPacket, sizeof( xNTPPacket ), 0, &xAddress, sizeof( xAddress ) );
+ }
+ break;
+
+ case EStatusPause:
+ break;
+
+ case EStatusFailed:
+ break;
+ }
+
+ #if( ipconfigUSE_CALLBACKS != 0 )
+ {
+ xSemaphoreTake( xNTPWakeupSem, 5000 );
+ }
+ #else
+ {
+ uint32_t xAddressSize;
+ BaseType_t xReturned;
+
+ xAddressSize = sizeof( xAddress );
+ xReturned = FreeRTOS_recvfrom( xUDPSocket, ( void * ) cRecvBuffer, sizeof( cRecvBuffer ), 0, &xAddress, &xAddressSize );
+ switch( xReturned )
+ {
+ case 0:
+ case -pdFREERTOS_ERRNO_EAGAIN:
+ case -pdFREERTOS_ERRNO_EINTR:
+ break;
+ default:
+ if( xReturned < sizeof( xNTPPacket ) )
+ {
+ FreeRTOS_printf( ( "FreeRTOS_recvfrom: returns %ld\n", xReturned ) );
+ }
+ else
+ {
+ prvReadTime( ( struct SNtpPacket *)cRecvBuffer );
+ if( xStatus != EStatusPause )
+ {
+ xStatus = EStatusPause;
+ }
+ }
+ break;
+ }
+ }
+ #endif
+ }
+}
+/*-----------------------------------------------------------*/
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_FTP_commands.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_FTP_commands.h
new file mode 100644
index 000000000..f11675f5d
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_FTP_commands.h
@@ -0,0 +1,165 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+#ifndef __FTPCMD_H__
+
+#define __FTPCMD_H__
+
+#define REPL_110 "110 Restart marker reply.\r\n"
+#define REPL_120 "120 Try again in 2 minutes.\r\n"
+#define REPL_125 "125 Data connection already open; transfer starting.\r\n"
+#define REPL_150 "150 File status okay; about to open data connection.\r\n"
+#define REPL_200 "200 NOOP command successful.\r\n"
+#define REPL_200_PROGRESS "200 NOOP: data transfer in progress.\r\n"
+#define REPL_202 "202 Command not implemented, superfluous at this site.\r\n"
+#define REPL_211 "221 System status, or system help reply.\r\n"
+#define REPL_211_STATUS "221-status of %s.\r\n"
+#define REPL_211_END "221 End of status.\r\n"
+#define REPL_212 "212 Directory status.\r\n"
+#define REPL_213 "213 File status.\r\n"
+#define REPL_214 "214 Help message.\r\n"
+#define REPL_214_END "214 End Help message.\r\n"
+#define REPL_215 "215 %s system type.\r\n"
+#define REPL_220 "220 Service ready for new user.\r\n"
+#define REPL_221 "221 Service closing control connection.\r\n"
+#define REPL_225 "225 Data connection open; no transfer in progress.\r\n"
+#define REPL_226 "226 Closing data connection.\r\n"
+#define REPL_227 "227 Entering Passive Mode (%s,%s,%s,%s,%s,%s).\r\n"
+#define REPL_227_D "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u).\r\n"
+#define REPL_230 "230 User logged in, proceed.\r\n"
+#define REPL_250 "250 Requested file action okay, completed.\r\n"
+#define REPL_257 "257 %s created.\r\n"
+// #define REPL_257_PWD "257 \"%s\" is current working dir.\r\n"
+#define REPL_257_PWD "257 \"%s\"\r\n"
+#define REPL_331 "331 Only anonymous user is accepted.\r\n"
+#define REPL_331_ANON "331 Anonymous login okay\r\n"
+#define REPL_332 "332 Need account for login.\r\n"
+#define REPL_350 "350 Requested file action pending further information.\r\n"
+#define REPL_421 "421 Service not available, closing control connection.\r\n"
+#define REPL_425 "425 Can't open data connection.\r\n"
+#define REPL_426 "426 Connection closed; transfer aborted.\r\n"
+#define REPL_450 "450 Requested file action not taken.\r\n"
+#define REPL_451 "451 Requested action aborted. Local error in processing.\r\n"
+#define REPL_452 "452 Requested action not taken.\r\n"
+#define REPL_500 "500 Syntax error, command unrecognized.\r\n"
+#define REPL_501 "501 Syntax error in parameters or arguments.\r\n"
+#define REPL_502 "502 Command not implemented.\r\n"
+#define REPL_503 "503 Bad sequence of commands.\r\n"
+#define REPL_504 "504 Command not implemented for that parameter.\r\n"
+#define REPL_530 "530 Not logged in.\r\n"
+#define REPL_532 "532 Need account for storing files.\r\n"
+#define REPL_550 "550 Requested action not taken.\r\n"
+#define REPL_551 "551 Requested action aborted. Page type unknown.\r\n"
+#define REPL_552 "552 Requested file action aborted.\r\n"
+#define REPL_553 "553 Requested action not taken.\r\n"
+#define REPL_553_READ_ONLY "553 Read-only file-system.\r\n"
+
+enum EFTPCommand {
+ ECMD_USER,
+ ECMD_PASS,
+ ECMD_ACCT,
+ ECMD_CWD,
+ ECMD_CDUP,
+ ECMD_SMNT,
+ ECMD_QUIT,
+ ECMD_REIN,
+ ECMD_PORT,
+ ECMD_PASV,
+ ECMD_TYPE,
+ ECMD_STRU,
+ ECMD_MODE,
+ ECMD_RETR,
+ ECMD_STOR,
+ ECMD_STOU,
+ ECMD_APPE,
+ ECMD_ALLO,
+ ECMD_REST,
+ ECMD_RNFR,
+ ECMD_RNTO,
+ ECMD_ABOR,
+ ECMD_SIZE,
+ ECMD_MDTM,
+ ECMD_DELE,
+ ECMD_RMD,
+ ECMD_MKD,
+ ECMD_PWD,
+ ECMD_LIST,
+ ECMD_NLST,
+ ECMD_SITE,
+ ECMD_SYST,
+ ECMD_FEAT,
+ ECMD_STAT,
+ ECMD_HELP,
+ ECMD_NOOP,
+ ECMD_EMPTY,
+ ECMD_CLOSE,
+ ECMD_UNKNOWN,
+};
+
+typedef struct xFTP_COMMAND {
+ BaseType_t xCommandLength;
+ const char pcCommandName[7];
+ const unsigned char ucCommandType;
+ const unsigned char checkLogin;
+ const unsigned char checkNullArg;
+} FTPCommand_t;
+
+#define FTP_CMD_COUNT (ECMD_UNKNOWN+1)
+
+extern const FTPCommand_t xFTPCommands[ FTP_CMD_COUNT ];
+
+#endif // __FTPCMD_H__
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_HTTP_commands.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_HTTP_commands.h
new file mode 100644
index 000000000..e8f6567b7
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_HTTP_commands.h
@@ -0,0 +1,99 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+#ifndef FREERTOS_HTTP_COMMANDS_H
+#define FREERTOS_HTTP_COMMANDS_H
+
+enum {
+ WEB_REPLY_OK = 200,
+ WEB_NO_CONTENT = 204,
+ WEB_BAD_REQUEST = 400,
+ WEB_UNAUTHORIZED = 401,
+ WEB_NOT_FOUND = 404,
+ WEB_GONE = 410,
+ WEB_PRECONDITION_FAILED = 412,
+ WEB_INTERNAL_SERVER_ERROR = 500,
+};
+
+enum EWebCommand {
+ ECMD_GET,
+ ECMD_HEAD,
+ ECMD_POST,
+ ECMD_PUT,
+ ECMD_DELETE,
+ ECMD_TRACE,
+ ECMD_OPTIONS,
+ ECMD_CONNECT,
+ ECMD_PATCH,
+ ECMD_UNK,
+};
+
+struct xWEB_COMMAND
+{
+ BaseType_t xCommandLength;
+ const char *pcCommandName;
+ const unsigned char ucCommandType;
+};
+
+#define WEB_CMD_COUNT (ECMD_UNK+1)
+
+extern const struct xWEB_COMMAND xWebCommands[WEB_CMD_COUNT];
+
+extern const char *webCodename (int aCode);
+
+#endif /* FREERTOS_HTTP_COMMANDS_H */
+
+
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_TCP_server.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_TCP_server.h
new file mode 100644
index 000000000..13a7f75b3
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_TCP_server.h
@@ -0,0 +1,157 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+/*
+ Some code which is common to TCP servers like HTTP en FTP
+*/
+
+#ifndef FREERTOS_TCP_SERVER_H
+#define FREERTOS_TCP_SERVER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef FTP_SERVER_USES_RELATIVE_DIRECTORY
+ #define FTP_SERVER_USES_RELATIVE_DIRECTORY 0
+#endif
+
+enum eSERVER_TYPE
+{
+ eSERVER_NONE,
+ eSERVER_HTTP,
+ eSERVER_FTP,
+};
+
+struct xFTP_CLIENT;
+
+#if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 )
+ extern void vApplicationFTPReceivedHook( const char *pcFileName, uint32_t ulSize, struct xFTP_CLIENT *pxFTPClient );
+ extern void vFTPReplyMessage( struct xFTP_CLIENT *pxFTPClient, const char *pcMessage );
+#endif /* ipconfigFTP_HAS_RECEIVED_HOOK != 0 */
+
+#if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 )
+ /*
+ * Function is called when a user name has been submitted.
+ * The function may return a string such as: "331 Please enter your password"
+ * or return NULL to use the default reply.
+ */
+ extern const char *pcApplicationFTPUserHook( const char *pcUserName );
+#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */
+
+#if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 )
+ /*
+ * Function is called when a password was received.
+ * Return positive value to allow the user
+ */
+ extern BaseType_t xApplicationFTPPasswordHook( const char *pcUserName, const char *pcPassword );
+#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */
+
+#if( ipconfigFTP_HAS_USER_PROPERTIES_HOOK != 0 )
+ /*
+ * The FTP server is asking for user-specific properties
+ */
+ typedef struct
+ {
+ uint16_t usPortNumber; /* For reference only. Host-endian. */
+ const char *pcRootDir;
+ BaseType_t xReadOnly;
+ }
+ FTPUserProperties_t;
+ extern void vApplicationFTPUserPropertiesHook( const char *pcUserName, FTPUserProperties_t *pxProperties );
+#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */
+
+#if( ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK != 0 )
+ /*
+ * A GET request is received containing a special character,
+ * usually a question mark.
+ * const char *pcURLData; // A request, e.g. "/request?limit=75"
+ * char *pcBuffer; // Here the answer can be written
+ * size_t uxBufferLength; // Size of the buffer
+ *
+ */
+ extern size_t uxApplicationHTTPHandleRequestHook( const char *pcURLData, char *pcBuffer, size_t uxBufferLength );
+#endif /* ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK */
+
+struct xSERVER_CONFIG
+{
+ enum eSERVER_TYPE eType; /* eSERVER_HTTP | eSERVER_FTP */
+ BaseType_t xPortNumber; /* e.g. 80, 8080, 21 */
+ BaseType_t xBackLog; /* e.g. 10, maximum number of connected TCP clients */
+ const char * const pcRootDir; /* Treat this directory as the root directory */
+};
+
+struct xTCP_SERVER;
+typedef struct xTCP_SERVER TCPServer_t;
+
+TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount );
+void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime );
+
+#if( ipconfigSUPPORT_SIGNALS != 0 )
+ /* FreeRTOS_TCPServerWork() calls select().
+ The two functions below provide a possibility to interrupt
+ the call to select(). After the interruption, resume
+ by calling FreeRTOS_TCPServerWork() again. */
+ BaseType_t FreeRTOS_TCPServerSignal( TCPServer_t *pxServer );
+ BaseType_t FreeRTOS_TCPServerSignalFromISR( TCPServer_t *pxServer, BaseType_t *pxHigherPriorityTaskWoken );
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* FREERTOS_TCP_SERVER_H */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_server_private.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_server_private.h
new file mode 100644
index 000000000..355aded2b
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_server_private.h
@@ -0,0 +1,217 @@
+/*
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
+ * Authors include Hein Tibosch and Richard Barry
+ *
+ *******************************************************************************
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *** ***
+ *** ***
+ *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
+ *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
+ *** download): ***
+ *** ***
+ *** FreeRTOS+TCP is functional and has been used in commercial products ***
+ *** for some time. Be aware however that we are still refining its ***
+ *** design, the source code does not yet quite conform to the strict ***
+ *** coding and style standards mandated by Real Time Engineers ltd., and ***
+ *** the documentation and testing is not necessarily complete. ***
+ *** ***
+ *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
+ *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
+ *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
+ *** under a license other than that described below. ***
+ *** ***
+ *** ***
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
+ *******************************************************************************
+ *
+ * FreeRTOS+TCP can be used under two different free open source licenses. The
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is
+ * executed, as follows:
+ *
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special
+ * License Arrangements heading of the FreeRTOS+TCP license information web
+ * page, then it can be used under the terms of the FreeRTOS Open Source
+ * License. If FreeRTOS+TCP is used on any other processor, then it can be used
+ * under the terms of the GNU General Public License V2. Links to the relevant
+ * licenses follow:
+ *
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
+ *
+ * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
+ * implied, expressed, or statutory.
+ *
+ * 1 tab == 4 spaces!
+ *
+ * http://www.FreeRTOS.org
+ * http://www.FreeRTOS.org/plus
+ * http://www.FreeRTOS.org/labs
+ *
+ */
+
+ /*
+ Some code which is common to TCP servers like HTTP and FTP
+*/
+
+#ifndef FREERTOS_SERVER_PRIVATE_H
+#define FREERTOS_SERVER_PRIVATE_H
+
+#define FREERTOS_NO_SOCKET NULL
+
+/* FreeRTOS+FAT */
+#include "ff_stdio.h"
+
+/* Each HTTP server has 1, at most 2 sockets */
+#define HTTP_SOCKET_COUNT 2
+
+/*
+ * ipconfigTCP_COMMAND_BUFFER_SIZE sets the size of:
+ * pcCommandBuffer': a buffer to receive and send TCP commands
+ *
+ * ipconfigTCP_FILE_BUFFER_SIZE sets the size of:
+ * pcFileBuffer' : a buffer to access the file system: read or write data.
+ *
+ * The buffers are both used for FTP as well as HTTP.
+ */
+
+#ifndef ipconfigTCP_COMMAND_BUFFER_SIZE
+ #define ipconfigTCP_COMMAND_BUFFER_SIZE ( 2048 )
+#endif
+
+#ifndef ipconfigTCP_FILE_BUFFER_SIZE
+ #define ipconfigTCP_FILE_BUFFER_SIZE ( 2048 )
+#endif
+
+struct xTCP_CLIENT;
+
+typedef BaseType_t ( * FTCPWorkFunction ) ( struct xTCP_CLIENT * /* pxClient */ );
+typedef void ( * FTCPDeleteFunction ) ( struct xTCP_CLIENT * /* pxClient */ );
+
+#define TCP_CLIENT_FIELDS \
+ enum eSERVER_TYPE eType; \
+ struct xTCP_SERVER *pxParent; \
+ Socket_t xSocket; \
+ const char *pcRootDir; \
+ FTCPWorkFunction fWorkFunction; \
+ FTCPDeleteFunction fDeleteFunction; \
+ struct xTCP_CLIENT *pxNextClient
+
+typedef struct xTCP_CLIENT
+{
+ /* This define contains fields which must come first within each of the client structs */
+ TCP_CLIENT_FIELDS;
+ /* --- Keep at the top --- */
+
+} TCPClient_t;
+
+struct xHTTP_CLIENT
+{
+ /* This define contains fields which must come first within each of the client structs */
+ TCP_CLIENT_FIELDS;
+ /* --- Keep at the top --- */
+
+ const char *pcUrlData;
+ const char *pcRestData;
+ char pcCurrentFilename[ ffconfigMAX_FILENAME ];
+ size_t uxBytesLeft;
+ FF_FILE *pxFileHandle;
+ union {
+ struct {
+ uint32_t
+ bReplySent : 1;
+ };
+ uint32_t ulFlags;
+ } bits;
+};
+
+typedef struct xHTTP_CLIENT HTTPClient_t;
+
+struct xFTP_CLIENT
+{
+ /* This define contains fields which must come first within each of the client structs */
+ TCP_CLIENT_FIELDS;
+ /* --- Keep at the top --- */
+
+ uint32_t ulRestartOffset;
+ uint32_t ulRecvBytes;
+ size_t uxBytesLeft; /* Bytes left to send */
+ uint32_t ulClientIP;
+ TickType_t xStartTime;
+ uint16_t usClientPort;
+ Socket_t xTransferSocket;
+ BaseType_t xTransType;
+ BaseType_t xDirCount;
+ FF_FindData_t xFindData;
+ FF_FILE *pxReadHandle;
+ FF_FILE *pxWriteHandle;
+ char pcCurrentDir[ ffconfigMAX_FILENAME ];
+ char pcFileName[ ffconfigMAX_FILENAME ];
+ char pcConnectionAck[ 128 ];
+ char pcClientAck[ 128 ];
+ union {
+ struct {
+ uint32_t
+ bHelloSent : 1,
+ bLoggedIn : 1,
+ bStatusUser : 1,
+ bInRename : 1,
+ bReadOnly : 1;
+ };
+ uint32_t ulFTPFlags;
+ } bits;
+ union {
+ struct {
+ uint32_t
+ bIsListen : 1, /* pdTRUE for passive data connections (using list()). */
+ bDirHasEntry : 1, /* pdTRUE if ff_findfirst() was successful. */
+ bClientConnected : 1, /* pdTRUE after connect() or accept() has succeeded. */
+ bEmptyFile : 1, /* pdTRUE if a connection-without-data was received. */
+ bHadError : 1; /* pdTRUE if a transfer got aborted because of an error. */
+ };
+ uint32_t ulConnFlags;
+ } bits1;
+};
+
+typedef struct xFTP_CLIENT FTPClient_t;
+
+BaseType_t xHTTPClientWork( TCPClient_t *pxClient );
+BaseType_t xFTPClientWork( TCPClient_t *pxClient );
+
+void vHTTPClientDelete( TCPClient_t *pxClient );
+void vFTPClientDelete( TCPClient_t *pxClient );
+
+BaseType_t xMakeAbsolute( struct xFTP_CLIENT *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName );
+BaseType_t xMakeRelative( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName );
+
+struct xTCP_SERVER
+{
+ SocketSet_t xSocketSet;
+ /* A buffer to receive and send TCP commands, either HTTP of FTP. */
+ char pcCommandBuffer[ ipconfigTCP_COMMAND_BUFFER_SIZE ];
+ /* A buffer to access the file system: read or write data. */
+ char pcFileBuffer[ ipconfigTCP_FILE_BUFFER_SIZE ];
+
+ #if( ipconfigUSE_FTP != 0 )
+ char pcNewDir[ ffconfigMAX_FILENAME ];
+ #endif
+ #if( ipconfigUSE_HTTP != 0 )
+ char pcContentsType[40]; /* Space for the msg: "text/javascript" */
+ char pcExtraContents[40]; /* Space for the msg: "Content-Length: 346500" */
+ #endif
+ BaseType_t xServerCount;
+ TCPClient_t *pxClients;
+ struct xSERVER
+ {
+ enum eSERVER_TYPE eType; /* eSERVER_HTTP | eSERVER_FTP */
+ const char *pcRootDir;
+ Socket_t xSocket;
+ } xServers[ 1 ];
+};
+
+#endif /* FREERTOS_SERVER_PRIVATE_H */
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPClient.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPClient.h
new file mode 100644
index 000000000..813539e6e
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPClient.h
@@ -0,0 +1,71 @@
+//
+// ntpClient.h
+//
+
+#ifndef __NTPCLIENT_H__
+
+#define __NTPCLIENT_H__
+
+#define NTP_PORT 123
+
+typedef uint32_t quint32;
+typedef int32_t qint32;
+typedef uint8_t quint8;
+typedef int8_t qint8;
+
+typedef union _SNtpFlags SNtpFlags;
+
+/**
+ * 64-bit NTP timestamp.
+ */
+struct __attribute__ ((__packed__)) _SNtpTimestamp {
+ /** Number of seconds passed since Jan 1 1900, in big-endian format. */
+ quint32 seconds;
+
+ /** Fractional time part, in <tt>1/0xFFFFFFFF</tt>s of a second. */
+ quint32 fraction;
+};
+
+typedef struct _SNtpTimestamp SNtpTimestamp;
+/**
+ * Mandatory part of an NTP packet
+ */
+struct SNtpPacket {
+ /** Flags. */
+ unsigned char flags; // value 0xDB : mode 3 (client), version 3, leap indicator unknown 3
+
+ /** Stratum of the clock. */
+ quint8 stratum; // value 0 : unspecified
+
+ /** Maximum interval between successive messages, in log2 seconds. Note that the value is signed. */
+ qint8 poll; // 10 means 1 << 10 = 1024 seconds
+
+ /** Precision of the clock, in log2 seconds. Note that the value is signed. */
+ qint8 precision; // 0xFA = 250 = 0.015625 seconds
+
+ /** Round trip time to the primary reference source, in NTP short format. */
+ qint32 rootDelay; // 0x5D2E = 23854 or (23854/65535)= 0.3640 sec
+
+ /** Nominal error relative to the primary reference source. */
+ qint32 rootDispersion; // 0x0008 CAC8 = 8.7912 seconds
+
+ /** Reference identifier (either a 4 character string or an IP address). */
+ qint8 referenceID[4]; // or just 0000
+
+ /** The time at which the clock was last set or corrected. */
+ SNtpTimestamp referenceTimestamp; // Current time
+
+ /** The time at which the request departed the client for the server. */
+ SNtpTimestamp originateTimestamp; // Keep 0
+
+ /** The time at which the request arrived at the server. */
+ SNtpTimestamp receiveTimestamp; // Keep 0
+
+ /** The time at which the reply departed the server for client. */
+ SNtpTimestamp transmitTimestamp;
+};
+
+/* Add this number to get secs since 1-1-1900 */
+#define TIME1970 2208988800UL
+
+#endif // __NTPCLIENT_H__
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPDemo.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPDemo.h
new file mode 100644
index 000000000..e75fb76aa
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPDemo.h
@@ -0,0 +1,11 @@
+/*
+ * A simple demo for NTP using FreeRTOS+TCP
+ */
+
+#ifndef NTPDEMO_H
+
+#define NTPDEMO_H
+
+void vStartNTPTask( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority );
+
+#endif \ No newline at end of file
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/readme.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/readme.txt
new file mode 100644
index 000000000..a90fb9e17
--- /dev/null
+++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/readme.txt
@@ -0,0 +1,18 @@
+Contains the files that implement FreeRTOS+TCP.
+
+User documentation, including an API reference is available on:
+http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/
+
+A description of the source code organisation is available on:
+http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Networking_Tutorial.html
+
+The porting guide is available on:
+http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FreeRTOS_TCP_Porting.html
+
+License information is available on:
+http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FreeRTOS_Plus_TCP_License.html
+
+At this time it is recommended to use BufferAllocation_2.c in which case it is
+essential to use the heap_4.c memory allocation scheme:
+http://www.FreeRTOS.org/a00111.html
+