1 /* 15.24 TCP MUST include 'exponential backoff' (check that it increases) for successive RTO values for sending data segments.  */
2 
3 /* Procedure
4    1. Client sends data to server.
5    2. When server receives packet for the first three times, check RTO and drop the packet.
6    3. Check if server receives data 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                   data_packet_counter;
36 
37 /* Define thread prototypes.  */
38 
39 static void    ntest_0_entry(ULONG thread_input);
40 static void    ntest_1_entry(ULONG thread_input);
41 static void    ntest_0_connect_received(NX_TCP_SOCKET *server_socket, UINT port);
42 static void    ntest_0_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_24(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_24_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     data_packet_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                      3, 3, 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                      4, 4, 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 ULONG        actual_status;
130 NX_PACKET    *my_packet;
131 
132     /* Print out test information banner.  */
133     printf("NetX Test:   TCP Spec 15.24 Test.......................................");
134 
135     /* Check for earlier error.  */
136     if(error_counter)
137     {
138         printf("ERROR!\n");
139         test_control_return(1);
140     }
141 
142     /* Ensure the IP instance has been initialized.  */
143     status = nx_ip_status_check(&ip_0, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE);
144 
145     /* Check for error.  */
146     if(status)
147         error_counter++;
148 
149     /* Create a socket.  */
150     status = nx_tcp_socket_create(&ip_0, &server_socket, "Server Socket",
151                                   NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 200,
152                                   NX_NULL, ntest_0_disconnect_received);
153 
154     /* Check for error.  */
155     if(status)
156         error_counter++;
157 
158     /* Setup this thread to listen.  */
159     status = nx_tcp_server_socket_listen(&ip_0, 12, &server_socket, 5, ntest_0_connect_received);
160 
161     /* Check for error.  */
162     if(status)
163         error_counter++;
164 
165     /* If accept return successfully, the connection has established.  */
166     status = nx_tcp_server_socket_accept(&server_socket, NX_IP_PERIODIC_RATE);
167 
168     /* Check for error.  */
169     if(status)
170         error_counter++;
171 
172     /* Init transmit configure.  */
173     status = nx_tcp_socket_transmit_configure(&server_socket, server_socket.nx_tcp_socket_transmit_queue_maximum,
174                                               server_socket.nx_tcp_socket_timeout_rate, server_socket.nx_tcp_socket_timeout_max_retries, 1);
175 
176     /* Check for error.  */
177     if(status)
178         error_counter++;
179 
180     /* Create a packet to send.  */
181     status = nx_packet_allocate(&pool_0, &my_packet, NX_TCP_PACKET, NX_IP_PERIODIC_RATE);
182 
183     /* Check for error.  */
184     if(status)
185         error_counter++;
186 
187     status = nx_packet_data_append(my_packet, MSG, 20, &pool_0, NX_IP_PERIODIC_RATE);
188 
189     /* Check for error.  */
190     if(status)
191         error_counter++;
192 
193     advanced_packet_process_callback = my_packet_process_15_24;
194 
195     /* Send packet to server.  */
196     status = nx_tcp_socket_send(&server_socket , my_packet, NX_IP_PERIODIC_RATE);
197 
198     /* Check for error.  */
199     if(status)
200         error_counter++;
201 
202     /* Wait for the retransmit.  */
203     tx_thread_suspend(&ntest_0);
204 
205     /* Disconnect the server socket.  */
206     status = nx_tcp_socket_disconnect(&server_socket, NX_IP_PERIODIC_RATE);
207 
208     /* Check for error.  */
209     if(status)
210         error_counter++;
211 
212     status = nx_tcp_server_socket_unaccept(&server_socket);
213 
214     /* Check for error.  */
215     if(status)
216         error_counter++;
217 
218     /* Unlisten on the server port.  */
219     status = nx_tcp_server_socket_unlisten(&ip_0, 12);
220 
221     /* Check for error.  */
222     if (status)
223         error_counter++;
224 
225     /* Delete the socket.  */
226     status = nx_tcp_socket_delete(&server_socket);
227 
228     /* Check for error.  */
229     if(status)
230         error_counter++;
231 }
232 
ntest_1_entry(ULONG thread_input)233 static void    ntest_1_entry(ULONG thread_input)
234 {
235 UINT         status;
236 NX_PACKET    *rcv_packet_ptr;
237 
238     /* Create a socket.  */
239     status = nx_tcp_socket_create(&ip_1, &client_socket, "Client Socket",
240                                   NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 300,
241                                   NX_NULL, NX_NULL);
242 
243     /* Check for error.  */
244     if(status)
245         error_counter++;
246 
247     /* Bind the socket.  */
248     status = nx_tcp_client_socket_bind(&client_socket, 12, NX_IP_PERIODIC_RATE);
249 
250     /* Check for error.  */
251     if(status)
252         error_counter++;
253 
254     /* Attempt to connect the socket.  */
255     status = nx_tcp_client_socket_connect(&client_socket, IP_ADDRESS(1, 2, 3, 4), 12, 2 * NX_IP_PERIODIC_RATE);
256 
257     /* Check for error.  */
258     if(status)
259         error_counter++;
260 
261     /* Wait until retransmit.  */
262     tx_thread_suspend(&ntest_1);
263 
264     status = nx_tcp_socket_receive(&client_socket, &rcv_packet_ptr, 2 * NX_IP_PERIODIC_RATE);
265 
266     /* Check for error.  */
267     if(status)
268         error_counter++;
269     else
270     {
271         /* Check data length and payload */
272         if((rcv_packet_ptr -> nx_packet_length == 20) &&
273             (!memcmp(rcv_packet_ptr -> nx_packet_prepend_ptr, MSG, 20)))
274             data_packet_counter++;
275 
276         /* Release the packet.  */
277         nx_packet_release(rcv_packet_ptr);
278     }
279 
280     /* Disconnect this socket.  */
281     status = nx_tcp_socket_disconnect(&client_socket, NX_IP_PERIODIC_RATE);
282 
283     /* Check for error.  */
284     if(status)
285         error_counter++;
286 
287     /* Unbind the socket.  */
288     status = nx_tcp_client_socket_unbind(&client_socket);
289 
290     /* Check for error.  */
291     if(status)
292         error_counter++;
293 
294     /* Delete the socket.  */
295     status = nx_tcp_socket_delete(&client_socket);
296 
297     /* Check for error.  */
298     if(status)
299         error_counter++;
300 
301     /* Determine if the test was successful.  */
302     if(error_counter || (drop_counter != 2) || (data_packet_counter != 1))
303     {
304         printf("ERROR!\n");
305         test_control_return(1);
306     }
307     else
308     {
309         printf("SUCCESS!\n");
310         test_control_return(0);
311     }
312 }
313 
ntest_0_connect_received(NX_TCP_SOCKET * socket_ptr,UINT port)314 static void    ntest_0_connect_received(NX_TCP_SOCKET *socket_ptr, UINT port)
315 {
316 
317     /* Check for the proper socket and port.  */
318     if((socket_ptr != &server_socket) || (port != 12))
319         error_counter++;
320 }
321 
ntest_0_disconnect_received(NX_TCP_SOCKET * socket)322 static void    ntest_0_disconnect_received(NX_TCP_SOCKET *socket)
323 {
324 
325     /* Check for proper disconnected socket.  */
326     if(socket != &server_socket)
327         error_counter++;
328 }
329 
my_packet_process_15_24(NX_IP * ip_ptr,NX_PACKET * packet_ptr,UINT * operation_ptr,UINT * delay_ptr)330 static UINT    my_packet_process_15_24(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr)
331 {
332     /* Drop packet three times.  */
333     if ((packet_ptr -> nx_packet_length - 40 == 20) && (!memcmp(packet_ptr -> nx_packet_prepend_ptr + 40, MSG, 20)))
334     {
335 
336         if(drop_counter < 2)
337         {
338 
339             /* Check if successive RTO increases as 'exponential backoff'.  */
340             if(server_socket.nx_tcp_socket_timeout != (server_socket.nx_tcp_socket_timeout_rate << (drop_counter * server_socket.nx_tcp_socket_timeout_shift)))
341             {
342                 error_counter++;
343             }
344 
345             *operation_ptr = NX_RAMDRIVER_OP_DROP;
346 
347             drop_counter++;
348         }
349         else
350         {
351             advanced_packet_process_callback = NX_NULL;
352 
353             /* Wake up server and client thread.  */
354             tx_thread_resume(&ntest_0);
355             tx_thread_resume(&ntest_1);
356         }
357     }
358 
359     return NX_TRUE;
360 }
361 #else
362 
363 #ifdef CTEST
test_application_define(void * first_unused_memory)364 VOID test_application_define(void *first_unused_memory)
365 #else
366 void    netx_15_24_application_define(void *first_unused_memory)
367 #endif
368 {
369 
370     /* Print out test information banner.  */
371     printf("NetX Test:   TCP Spec 15.24 Test.......................................N/A\n");
372 
373     test_control_return(3);
374 }
375 #endif
376