1 /* 15.25 TCP MUST include exponential backoff(check that it increases) for successive RTO values for sending SYN segments.  */
2 
3 /* Procedure
4    1. Client sends SYN to server.
5    2. When server receives SYN packet for the first three times, check RTO and drop the packet.
6    3. Check if client connects to server successfully.  */
7 
8 #include   "tx_api.h"
9 #include   "nx_api.h"
10 #include   "nx_tcp.h"
11 #include   "nx_ram_network_driver_test_1500.h"
12 extern void    test_control_return(UINT status);
13 
14 #if !defined(NX_DISABLE_IPV4)
15 
16 #define     DEMO_STACK_SIZE    2048
17 
18 #define MSG "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
19 
20 /* Define the ThreadX and NetX object control blocks...  */
21 
22 static TX_THREAD               ntest_0;
23 static TX_THREAD               ntest_1;
24 
25 static NX_PACKET_POOL          pool_0;
26 static NX_IP                   ip_0;
27 static NX_IP                   ip_1;
28 static NX_TCP_SOCKET           client_socket;
29 static NX_TCP_SOCKET           server_socket;
30 
31 /* Define the counters used in the demo application...  */
32 
33 static ULONG                   error_counter;
34 static ULONG                   drop_counter;
35 static ULONG                   syn_counter;
36 
37 /* Define thread prototypes.  */
38 
39 static void    ntest_1_entry(ULONG thread_input);
40 static void    ntest_0_entry(ULONG thread_input);
41 static void    ntest_1_connect_received(NX_TCP_SOCKET *server_socket, UINT port);
42 static void    ntest_1_disconnect_received(NX_TCP_SOCKET *server_socket);
43 extern void    _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
44 extern void    _nx_ram_network_driver_1500(struct NX_IP_DRIVER_STRUCT *driver_req);
45 extern UINT    (*advanced_packet_process_callback)(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr);
46 static UINT    my_packet_process_15_25(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr);
47 
48 /* Define what the initial system looks like.  */
49 
50 #ifdef CTEST
test_application_define(void * first_unused_memory)51 VOID test_application_define(void *first_unused_memory)
52 #else
53 void           netx_15_25_application_define(void *first_unused_memory)
54 #endif
55 {
56 CHAR       *pointer;
57 UINT       status;
58 
59     /* Setup the working pointer.  */
60     pointer = (CHAR *) first_unused_memory;
61 
62     error_counter = 0;
63     drop_counter = 0;
64     syn_counter = 0;
65 
66     /* Create the main thread.  */
67     tx_thread_create(&ntest_0, "thread 0", ntest_0_entry, 0,
68                      pointer, DEMO_STACK_SIZE,
69                      4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
70 
71     pointer = pointer + DEMO_STACK_SIZE;
72 
73     /* Create the main thread.  */
74     tx_thread_create(&ntest_1, "thread 1", ntest_1_entry, 0,
75                      pointer, DEMO_STACK_SIZE,
76                      3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
77 
78     pointer = pointer + DEMO_STACK_SIZE;
79 
80     /* Initialize the NetX system.  */
81     nx_system_initialize();
82 
83     /* Create a packet pool.  */
84     status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 512, pointer, 8192);
85     pointer = pointer + 8192;
86 
87     if(status)
88         error_counter++;
89 
90     /* Create an IP instance.  */
91     status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver_1500,
92                           pointer, 2048, 1);
93     pointer = pointer + 2048;
94 
95     /* Create another IP instance.  */
96     status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
97                            pointer, 2048, 1);
98     pointer = pointer + 2048;
99 
100     if(status)
101         error_counter++;
102 
103     /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
104     status = nx_arp_enable(&ip_0, (void *) pointer, 1024);
105     pointer = pointer + 1024;
106 
107     /* Enable ARP and supply ARP cache memory for IP Instance 1.  */
108     status += nx_arp_enable(&ip_1, (void *) pointer, 1024);
109     pointer = pointer + 1024;
110 
111     /* Check ARP enable status.  */
112     if(status)
113         error_counter++;
114 
115     /* Enable TCP processing for both IP instances.  */
116     status = nx_tcp_enable(&ip_0);
117     status += nx_tcp_enable(&ip_1);
118 
119     /* Check TCP enable status.  */
120     if(status)
121         error_counter++;
122 }
123 
124 /* Define the test threads.  */
125 
ntest_0_entry(ULONG thread_input)126 static void    ntest_0_entry(ULONG thread_input)
127 {
128 UINT       status;
129 
130     /* Create a socket.  */
131     status = nx_tcp_socket_create(&ip_0, &client_socket, "Client Socket",
132                                   NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 300,
133                                   NX_NULL, NX_NULL);
134 
135     /* Check for error.  */
136     if(status)
137         error_counter++;
138 
139     /* Bind the socket.  */
140     status = nx_tcp_client_socket_bind(&client_socket, 12, NX_IP_PERIODIC_RATE);
141 
142     /* Check for error.  */
143     if(status)
144         error_counter++;
145 
146     /* Init transmit configure.  */
147     status = nx_tcp_socket_transmit_configure(&client_socket, client_socket.nx_tcp_socket_transmit_queue_maximum,
148                                               client_socket.nx_tcp_socket_timeout_rate, client_socket.nx_tcp_socket_timeout_max_retries, 1);
149 
150     /* Check for error.  */
151     if(status)
152         error_counter++;
153 
154     advanced_packet_process_callback = my_packet_process_15_25;
155 
156     /* Attempt to connect the socket.  */
157     status = nx_tcp_client_socket_connect(&client_socket, IP_ADDRESS(1, 2, 3, 5), 12, 100 * NX_IP_PERIODIC_RATE);
158 
159     /* Check for error.  */
160     if(status)
161         error_counter++;
162 
163     /* Disconnect this socket.  */
164     status = nx_tcp_socket_disconnect(&client_socket, NX_IP_PERIODIC_RATE);
165 
166     /* Check for error.  */
167     if(status)
168         error_counter++;
169 
170     /* Unbind the socket.  */
171     status = nx_tcp_client_socket_unbind(&client_socket);
172 
173     /* Check for error.  */
174     if(status)
175         error_counter++;
176 
177     /* Delete the socket.  */
178     status = nx_tcp_socket_delete(&client_socket);
179 
180     /* Check for error.  */
181     if(status)
182         error_counter++;
183 
184     /* Determine if the test was successful.  */
185     if(error_counter || (drop_counter != 1) || (syn_counter != 2))
186     {
187         printf("ERROR!\n");
188         test_control_return(1);
189     }
190     else
191     {
192         printf("SUCCESS!\n");
193         test_control_return(0);
194     }
195 }
196 
ntest_1_entry(ULONG thread_input)197 static void    ntest_1_entry(ULONG thread_input)
198 {
199 UINT       status;
200 ULONG      actual_status;
201 
202     /* Print out test information banner.  */
203     printf("NetX Test:   TCP Spec 15.25 Test.......................................");
204 
205     /* Check for earlier error.  */
206     if(error_counter)
207     {
208         printf("ERROR!\n");
209         test_control_return(1);
210     }
211 
212     /* Ensure the IP instance has been initialized.  */
213     status = nx_ip_status_check(&ip_1, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE);
214 
215     /* Check for error.  */
216     if(status)
217         error_counter++;
218 
219     /* Create a socket.  */
220     status = nx_tcp_socket_create(&ip_1, &server_socket, "Server Socket",
221                                   NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 200,
222                                   NX_NULL, ntest_1_disconnect_received);
223 
224     /* Check for error.  */
225     if(status)
226         error_counter++;
227 
228     /* Setup this thread to listen.  */
229     status = nx_tcp_server_socket_listen(&ip_1, 12, &server_socket, 5, ntest_1_connect_received);
230 
231     /* Check for error.  */
232     if(status)
233         error_counter++;
234 
235     /* If accept return successfully, the connection has established.  */
236     status = nx_tcp_server_socket_accept(&server_socket, 100 * NX_IP_PERIODIC_RATE);
237 
238     /* Check for error.  */
239     if(status)
240         error_counter++;
241 
242     /* Disconnect the server socket.  */
243     status = nx_tcp_socket_disconnect(&server_socket, NX_IP_PERIODIC_RATE);
244 
245     /* Check for error.  */
246     if(status)
247         error_counter++;
248 
249     status = nx_tcp_server_socket_unaccept(&server_socket);
250 
251     /* Check for error.  */
252     if(status)
253         error_counter++;
254 
255     /* Unlisten on the server port.  */
256     status = nx_tcp_server_socket_unlisten(&ip_1, 12);
257 
258     /* Check for error.  */
259     if (status)
260         error_counter++;
261 
262     /* Delete the socket.  */
263     status = nx_tcp_socket_delete(&server_socket);
264 
265     /* Check for error.  */
266     if(status)
267         error_counter++;
268 }
269 
ntest_1_connect_received(NX_TCP_SOCKET * socket_ptr,UINT port)270 static void    ntest_1_connect_received(NX_TCP_SOCKET *socket_ptr, UINT port)
271 {
272 
273     /* Check for the proper socket and port.  */
274     if((socket_ptr != &server_socket) || (port != 12))
275         error_counter++;
276 }
277 
ntest_1_disconnect_received(NX_TCP_SOCKET * socket)278 static void    ntest_1_disconnect_received(NX_TCP_SOCKET *socket)
279 {
280 
281     /* Check for proper disconnected socket.  */
282     if(socket != &server_socket)
283         error_counter++;
284 }
285 
my_packet_process_15_25(NX_IP * ip_ptr,NX_PACKET * packet_ptr,UINT * operation_ptr,UINT * delay_ptr)286 static UINT    my_packet_process_15_25(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr)
287 {
288 NX_TCP_HEADER   *header_ptr;
289 
290     header_ptr = (NX_TCP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr + 20);
291 
292     NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_3);
293 
294     /* If this is a tcp packet but not an ARP packet or other kind packet. */
295     if(packet_ptr -> nx_packet_length >= 40)
296     {
297         /* Drop packet three times.  */
298         if((header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) && !(header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) && !(header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT))
299         {
300 
301             syn_counter++;
302 
303             if(drop_counter == 0)
304             {
305 
306                 *operation_ptr = NX_RAMDRIVER_OP_DROP;
307 
308                 drop_counter++;
309             }
310             else
311             {
312                 /* Check if successive RTO increases as 'exponential backoff'.  */
313                 if(client_socket.nx_tcp_socket_timeout != (client_socket.nx_tcp_socket_timeout_rate << (drop_counter * client_socket.nx_tcp_socket_timeout_shift)))
314                 {
315                     error_counter++;
316                 }
317 
318                 advanced_packet_process_callback = NX_NULL;
319 
320                 /* Wake up server and client thread.  */
321                 tx_thread_resume(&ntest_0);
322                 tx_thread_resume(&ntest_1);
323             }
324 
325             NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_3);
326         }
327     }
328     return NX_TRUE;
329 }
330 #else
331 
332 #ifdef CTEST
test_application_define(void * first_unused_memory)333 VOID test_application_define(void *first_unused_memory)
334 #else
335 void    netx_15_25_application_define(void *first_unused_memory)
336 #endif
337 {
338 
339     /* Print out test information banner.  */
340     printf("NetX Test:   TCP Spec 15.25 Test.......................................N/A\n");
341 
342     test_control_return(3);
343 }
344 #endif