1 /*
2  * FreeRTOS V202212.00
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * https://www.FreeRTOS.org
23  * https://github.com/FreeRTOS
24  *
25  */
26 
27 /*
28  * This project is a cut down version of the project described on the following
29  * link.  Only the simple UDP client and server and the TCP echo clients are
30  * included in the build:
31  * https://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html
32  */
33 
34 /* Standard includes. */
35 #include <stdio.h>
36 #include <time.h>
37 #include <unistd.h>
38 
39 /* FreeRTOS includes. */
40 #include <FreeRTOS.h>
41 #include "task.h"
42 
43 /* Demo application includes. */
44 #include "FreeRTOS_IP.h"
45 #include "FreeRTOS_Sockets.h"
46 /*#include "SimpleUDPClientAndServer.h" */
47 /*#include "SimpleTCPEchoServer.h" */
48 /*#include "TCPEchoClient_SingleTasks.h" */
49 /*#include "logging.h" */
50 #include "TCPEchoClient_SingleTasks.h"
51 
52 /* Simple UDP client and server task parameters. */
53 #define mainSIMPLE_UDP_CLIENT_SERVER_TASK_PRIORITY    ( tskIDLE_PRIORITY )
54 #define mainSIMPLE_UDP_CLIENT_SERVER_PORT             ( 5005UL )
55 
56 /* Echo client task parameters - used for both TCP and UDP echo clients. */
57 #define mainECHO_CLIENT_TASK_STACK_SIZE               ( configMINIMAL_STACK_SIZE * 2 )
58 #define mainECHO_CLIENT_TASK_PRIORITY                 ( tskIDLE_PRIORITY + 1 )
59 
60 /* Echo server task parameters. */
61 #define mainECHO_SERVER_TASK_STACK_SIZE               ( configMINIMAL_STACK_SIZE * 2 )
62 #define mainECHO_SERVER_TASK_PRIORITY                 ( tskIDLE_PRIORITY + 1 )
63 
64 /* Define a name that will be used for LLMNR and NBNS searches. */
65 #define mainHOST_NAME                                 "RTOSDemo"
66 #define mainDEVICE_NICK_NAME                          "linux_demo"
67 
68 /* Set the following constants to 1 or 0 to define which tasks to include and
69  * exclude:
70  *
71  * mainCREATE_TCP_ECHO_TASKS_SINGLE:  When set to 1 a set of tasks are created that
72  * send TCP echo requests to the standard echo port (port 7), then wait for and
73  * verify the echo reply, from within the same task (Tx and Rx are performed in the
74  * same RTOS task).  The IP address of the echo server must be configured using the
75  * configECHO_SERVER_ADDR0 to configECHO_SERVER_ADDR3 constants in
76  * FreeRTOSConfig.h.
77  *
78  */
79 #define mainCREATE_TCP_ECHO_TASKS_SINGLE              1
80 /*-----------------------------------------------------------*/
81 
82 /*
83  * Just seeds the simple pseudo random number generator.
84  */
85 static void prvSRand( UBaseType_t ulSeed );
86 
87 /*
88  * Miscellaneous initialisation including preparing the logging and seeding the
89  * random number generator.
90  */
91 static void prvMiscInitialisation( void );
92 
93 /* The default IP and MAC address used by the demo.  The address configuration
94  * defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is
95  * 1 but a DHCP server could not be contacted.  See the online documentation for
96  * more information. */
97 static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 };
98 static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 };
99 static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 };
100 static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 };
101 
102 /* Set the following constant to pdTRUE to log using the method indicated by the
103  * name of the constant, or pdFALSE to not log using the method indicated by the
104  * name of the constant.  Options include to standard out (xLogToStdout), to a disk
105  * file (xLogToFile), and to a UDP port (xLogToUDP).  If xLogToUDP is set to pdTRUE
106  * then UDP messages are sent to the IP address configured as the echo server
107  * address (see the configECHO_SERVER_ADDR0 definitions in FreeRTOSConfig.h) and
108  * the port number set by configPRINT_PORT in FreeRTOSConfig.h. */
109 const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE;
110 
111 /* Default MAC address configuration.  The demo creates a virtual network
112  * connection that uses this MAC address by accessing the raw Ethernet data
113  * to and from a real network connection on the host PC.  See the
114  * configNETWORK_INTERFACE_TO_USE definition for information on how to configure
115  * the real network connection to use. */
116 const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 };
117 
118 /* Use by the pseudo random number generator. */
119 static UBaseType_t ulNextRand;
120 
121 #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 )
122 
123 /* In case multiple interfaces are used, define them statically. */
124 
125 /* There is only 1 physical interface. */
126     static NetworkInterface_t xInterfaces[ 1 ];
127 
128 /* It will have several end-points. */
129     static NetworkEndPoint_t xEndPoints[ 4 ];
130 
131 #endif /* if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */
132 
133 
134 /*-----------------------------------------------------------*/
135 
main_tcp_echo_client_tasks(void)136 void main_tcp_echo_client_tasks( void )
137 {
138     BaseType_t xResult;
139     const uint32_t ulLongTime_ms = pdMS_TO_TICKS( 1000UL );
140 
141     /*
142      * Instructions for using this project are provided on:
143      * https://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html
144      */
145 
146     /* Miscellaneous initialisation including preparing the logging and seeding
147      * the random number generator. */
148     prvMiscInitialisation();
149 
150     /* Initialise the network interface.
151      *
152      ***NOTE*** Tasks that use the network are created in the network event hook
153      * when the network is connected and ready for use (see the definition of
154      * vApplicationIPNetworkEventHook() below).  The address values passed in here
155      * are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1
156      * but a DHCP server cannot be	contacted. */
157 
158     /* Initialise the network interface.*/
159     FreeRTOS_debug_printf( ( "FreeRTOS_IPInit\r\n" ) );
160 
161     #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 )
162         extern NetworkInterface_t * pxLibslirp_FillInterfaceDescriptor( BaseType_t xEMACIndex,
163                                                                         NetworkInterface_t * pxInterface );
164         pxLibslirp_FillInterfaceDescriptor( 0, &( xInterfaces[ 0 ] ) );
165 
166         /* === End-point 0 === */
167         FreeRTOS_FillEndPoint( &( xInterfaces[ 0 ] ), &( xEndPoints[ 0 ] ), ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );
168     #if ( ipconfigUSE_DHCP != 0 )
169         {
170             /* End-point 0 wants to use DHCPv4. */
171             xEndPoints[ 0 ].bits.bWantDHCP = pdTRUE;
172         }
173         #endif /* ( ipconfigUSE_DHCP != 0 ) */
174 
175         xResult = FreeRTOS_IPInit_Multi();
176     #else /* if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */
177         /* Using the old /single /IPv4 library, or using backward compatible mode of the new /multi library. */
178         xResult = FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );
179     #endif /* if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */
180 
181     configASSERT( xResult == pdTRUE );
182 
183     /* Start the RTOS scheduler. */
184     FreeRTOS_debug_printf( ( "vTaskStartScheduler\n" ) );
185     vTaskStartScheduler();
186     FreeRTOS_debug_printf( ( "Should not reach this point after scheduler\n" ) );
187 
188     /* If all is well, the scheduler will now be running, and the following
189      * line will never be reached.  If the following line does execute, then
190      * there was insufficient FreeRTOS heap memory available for the idle and/or
191      * timer tasks	to be created.  See the memory management section on the
192      * FreeRTOS web site for more details (this is standard text that is not not
193      * really applicable to the Linux simulator port). */
194     for( ; ; )
195     {
196         usleep( ulLongTime_ms * 1000 );
197     }
198 }
199 /*-----------------------------------------------------------*/
200 
201 /* Called by FreeRTOS+TCP when the network connects or disconnects.  Disconnect
202  * events are only received if implemented in the MAC driver. */
203 /* *INDENT-OFF* */
204 #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 )
vApplicationIPNetworkEventHook_Multi(eIPCallbackEvent_t eNetworkEvent,struct xNetworkEndPoint * pxEndPoint)205     void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent,
206                                                struct xNetworkEndPoint * pxEndPoint )
207 #else
208     void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
209 #endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */
210 /* *INDENT-ON* */
211 {
212     uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress;
213     char cBuffer[ 16 ];
214     static BaseType_t xTasksAlreadyCreated = pdFALSE;
215 
216     /* If the network has just come up...*/
217     if( eNetworkEvent == eNetworkUp )
218     {
219         /* Create the tasks that use the IP stack if they have not already been
220          * created. */
221         if( xTasksAlreadyCreated == pdFALSE )
222         {
223             /* See the comments above the definitions of these pre-processor
224              * macros at the top of this file for a description of the individual
225              * demo tasks. */
226 
227             #if ( mainCREATE_TCP_ECHO_TASKS_SINGLE == 1 )
228             {
229                 vStartTCPEchoClientTasks_SingleTasks( mainECHO_CLIENT_TASK_STACK_SIZE, mainECHO_CLIENT_TASK_PRIORITY );
230             }
231             #endif /* mainCREATE_TCP_ECHO_TASKS_SINGLE */
232 
233             xTasksAlreadyCreated = pdTRUE;
234         }
235 
236         /* Print out the network configuration, which may have come from a DHCP
237          * server. */
238         #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 )
239             FreeRTOS_GetEndPointConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress, pxNetworkEndPoints );
240         #else
241             FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress );
242         #endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */
243         FreeRTOS_inet_ntoa( ulIPAddress, cBuffer );
244         FreeRTOS_printf( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) );
245 
246         FreeRTOS_inet_ntoa( ulNetMask, cBuffer );
247         FreeRTOS_printf( ( "Subnet Mask: %s\r\n", cBuffer ) );
248 
249         FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer );
250         FreeRTOS_printf( ( "Gateway Address: %s\r\n", cBuffer ) );
251 
252         FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer );
253         FreeRTOS_printf( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) );
254     }
255     else
256     {
257         FreeRTOS_printf( ( "Application idle hook network down\n" ) );
258     }
259 }
260 /*-----------------------------------------------------------*/
261 
uxRand(void)262 UBaseType_t uxRand( void )
263 {
264     const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;
265 
266     /* Utility function to generate a pseudo random number. */
267 
268     ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;
269     return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL );
270 }
271 /*-----------------------------------------------------------*/
272 
prvSRand(UBaseType_t ulSeed)273 static void prvSRand( UBaseType_t ulSeed )
274 {
275     /* Utility function to seed the pseudo random number generator. */
276     ulNextRand = ulSeed;
277 }
278 /*-----------------------------------------------------------*/
279 
prvMiscInitialisation(void)280 static void prvMiscInitialisation( void )
281 {
282     time_t xTimeNow;
283     uint32_t ulRandomNumbers[ 4 ];
284 
285     /* Seed the random number generator. */
286     time( &xTimeNow );
287     FreeRTOS_debug_printf( ( "Seed for randomiser: %lu\n", xTimeNow ) );
288     prvSRand( ( uint32_t ) xTimeNow );
289 
290     ( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 0 ] );
291     ( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 1 ] );
292     ( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 2 ] );
293     ( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 3 ] );
294 
295     FreeRTOS_debug_printf( ( "Random numbers: %08X %08X %08X %08X\n",
296                              ulRandomNumbers[ 0 ],
297                              ulRandomNumbers[ 1 ],
298                              ulRandomNumbers[ 2 ],
299                              ulRandomNumbers[ 3 ] ) );
300 }
301 /*-----------------------------------------------------------*/
302 
303 #if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
304 
pcApplicationHostnameHook(void)305     const char * pcApplicationHostnameHook( void )
306     {
307         /* Assign the name "FreeRTOS" to this network node.  This function will
308          * be called during the DHCP: the machine will be registered with an IP
309          * address plus this name. */
310         return mainHOST_NAME;
311     }
312 
313 #endif
314 /*-----------------------------------------------------------*/
315 
316 #if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 )
317 
318     #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 )
xApplicationDNSQueryHook_Multi(struct xNetworkEndPoint * pxEndPoint,const char * pcName)319         BaseType_t xApplicationDNSQueryHook_Multi( struct xNetworkEndPoint * pxEndPoint,
320                                                    const char * pcName )
321     #else
322         BaseType_t xApplicationDNSQueryHook( const char * pcName )
323     #endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */
324     {
325         BaseType_t xReturn;
326 
327         /* Determine if a name lookup is for this node.  Two names are given
328          * to this node: that returned by pcApplicationHostnameHook() and that set
329          * by mainDEVICE_NICK_NAME. */
330         if( strcasecmp( pcName, pcApplicationHostnameHook() ) == 0 )
331         {
332             xReturn = pdPASS;
333         }
334         else if( strcasecmp( pcName, mainDEVICE_NICK_NAME ) == 0 )
335         {
336             xReturn = pdPASS;
337         }
338         else
339         {
340             xReturn = pdFAIL;
341         }
342 
343         return xReturn;
344     }
345 
346 #endif /* if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) */
347 
348 /*
349  * Callback that provides the inputs necessary to generate a randomized TCP
350  * Initial Sequence Number per RFC 6528.  THIS IS ONLY A DUMMY IMPLEMENTATION
351  * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION
352  * SYSTEMS.
353  */
ulApplicationGetNextSequenceNumber(uint32_t ulSourceAddress,uint16_t usSourcePort,uint32_t ulDestinationAddress,uint16_t usDestinationPort)354 extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,
355                                                     uint16_t usSourcePort,
356                                                     uint32_t ulDestinationAddress,
357                                                     uint16_t usDestinationPort )
358 {
359     ( void ) ulSourceAddress;
360     ( void ) usSourcePort;
361     ( void ) ulDestinationAddress;
362     ( void ) usDestinationPort;
363 
364     return uxRand();
365 }
366 
367 /*
368  * Supply a random number to FreeRTOS+TCP stack.
369  * THIS IS ONLY A DUMMY IMPLEMENTATION THAT RETURNS A PSEUDO RANDOM NUMBER
370  * SO IS NOT INTENDED FOR USE IN PRODUCTION SYSTEMS.
371  */
xApplicationGetRandomNumber(uint32_t * pulNumber)372 BaseType_t xApplicationGetRandomNumber( uint32_t * pulNumber )
373 {
374     *( pulNumber ) = uxRand();
375     return pdTRUE;
376 }
377