1 /* 1.21 TCP MUST send an ACK after receiving a FIN in FIN_WAIT_1 state. */
2
3 /* Procedure
4 1. Establish a connection by the "three-way handshake" procedure.
5 2. Server sends a FIN packet and becomes FIN_WAIT_1 state.
6 3. Delay the FIN packet and keep the server state to FIN_WAIT_1.
7 4. Client sends a FIN packet.
8 5. Check the packet is a FIN one.
9 6. Server replies an ACK packet.
10 7. Check the packet is an ACK one. */
11
12 #include "tx_api.h"
13 #include "nx_api.h"
14 #include "nx_tcp.h"
15 #include "nx_ram_network_driver_test_1500.h"
16 extern void test_control_return(UINT status);
17
18 #if !defined(NX_DISABLE_IPV4)
19
20 #define DEMO_STACK_SIZE 2048
21
22 /* Define the ThreadX and NetX object control blocks... */
23
24 static TX_THREAD ntest_0;
25 static TX_THREAD ntest_1;
26
27 static NX_PACKET_POOL pool_0;
28 static NX_IP ip_0;
29 static NX_IP ip_1;
30 static NX_TCP_SOCKET client_socket;
31 static NX_TCP_SOCKET server_socket;
32
33 /* Define the counters used in the test application... */
34
35 static ULONG error_counter;
36 static ULONG fin_counter;
37 static ULONG ack_counter;
38
39 /* Define thread prototypes. */
40
41 static void ntest_0_entry(ULONG thread_input);
42 static void ntest_1_entry(ULONG thread_input);
43 static void ntest_0_connect_received(NX_TCP_SOCKET *server_socket, UINT port);
44 static void ntest_0_disconnect_received(NX_TCP_SOCKET *server_socket);
45 extern void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
46 extern void _nx_ram_network_driver_1500(struct NX_IP_DRIVER_STRUCT *driver_req);
47 extern UINT (*advanced_packet_process_callback)(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr);
48 static UINT my_packet_process_1_21_01(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr);
49 static void my_tcp_packet_receive_1_21_01(NX_IP *ip_ptr, NX_PACKET *packet_ptr);
50 static void my_tcp_packet_receive_1_21_01_2(NX_IP *ip_ptr, NX_PACKET *packet_ptr);
51
52 /* Define what the initial system looks like. */
53
54 #ifdef CTEST
test_application_define(void * first_unused_memory)55 VOID test_application_define(void *first_unused_memory)
56 #else
57 void netx_1_21_01_application_define(void *first_unused_memory)
58 #endif
59 {
60 CHAR *pointer;
61 UINT status;
62
63 /* Setup the working pointer. */
64 pointer = (CHAR *) first_unused_memory;
65
66 error_counter = 0;
67 fin_counter = 0;
68 ack_counter = 0;
69
70 /* Create the main thread. */
71 tx_thread_create(&ntest_0, "thread 0", ntest_0_entry, 0,
72 pointer, DEMO_STACK_SIZE,
73 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
74
75 pointer = pointer + DEMO_STACK_SIZE;
76
77 /* Create the main thread. */
78 tx_thread_create(&ntest_1, "thread 1", ntest_1_entry, 0,
79 pointer, DEMO_STACK_SIZE,
80 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
81
82 pointer = pointer + DEMO_STACK_SIZE;
83
84 /* Initialize the NetX system. */
85 nx_system_initialize();
86
87 /* Create a packet pool. */
88 status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 256, pointer, 8192);
89 pointer = pointer + 8192;
90
91 if(status)
92 error_counter++;
93
94 /* Create an IP instance. */
95 status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver_1500,
96 pointer, 2048, 1);
97 pointer = pointer + 2048;
98
99 /* Create another IP instance. */
100 status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
101 pointer, 2048, 2);
102 pointer = pointer + 2048;
103
104 if(status)
105 error_counter++;
106
107 /* Enable ARP and supply ARP cache memory for IP Instance 0. */
108 status = nx_arp_enable(&ip_0, (void *) pointer, 1024);
109 pointer = pointer + 1024;
110 if(status)
111 error_counter++;
112
113 /* Enable ARP and supply ARP cache memory for IP Instance 1. */
114 status = nx_arp_enable(&ip_1, (void *) pointer, 1024);
115 pointer = pointer + 1024;
116 if(status)
117 error_counter++;
118
119 /* Enable TCP processing for both IP instances. */
120 status = nx_tcp_enable(&ip_0);
121 status += nx_tcp_enable(&ip_1);
122
123 /* Check TCP enable status. */
124 if(status)
125 error_counter++;
126 }
127
128 /* Define the test threads. */
129
ntest_0_entry(ULONG thread_input)130 static void ntest_0_entry(ULONG thread_input)
131 {
132 UINT status;
133 ULONG actual_status;
134
135 /* Print out test information banner. */
136 printf("NetX Test: TCP Spec 1.21.01 Test.....................................");
137
138 /* Check for earlier error. */
139 if(error_counter)
140 {
141 printf("ERROR!\n");
142 test_control_return(1);
143 }
144
145 /* Ensure the IP instance has been initialized. */
146 status = nx_ip_status_check(&ip_0, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE);
147
148 /* Check for error. */
149 if(status)
150 error_counter++;
151
152 /* Create a socket. */
153 status = nx_tcp_socket_create(&ip_0, &server_socket, "Server Socket",
154 NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 100,
155 NX_NULL, ntest_0_disconnect_received);
156
157 /* Check for error. */
158 if(status)
159 error_counter++;
160
161 /* Setup this thread to listen. */
162 status = nx_tcp_server_socket_listen(&ip_0, 12, &server_socket, 5, ntest_0_connect_received);
163
164 /* Check for error. */
165 if(status)
166 error_counter++;
167
168 /* Accept a client socket connection. */
169 status = nx_tcp_server_socket_accept(&server_socket, NX_IP_PERIODIC_RATE);
170
171 /* Check for error. */
172 if(status)
173 error_counter++;
174
175 /* Let the driver delay the FIN packet. */
176 advanced_packet_process_callback = my_packet_process_1_21_01;
177
178 /*Let the server socket check the FIN packet. */
179 ip_0.nx_ip_tcp_packet_receive = my_tcp_packet_receive_1_21_01;
180
181 /* Disconnect the server socket. */
182 status = nx_tcp_socket_disconnect(&server_socket, 2 * NX_IP_PERIODIC_RATE);
183
184 /* Check for error. */
185 if(status)
186 error_counter++;
187
188 /* Unaccept the server socket. */
189 status = nx_tcp_server_socket_unaccept(&server_socket);
190
191 /* Check for error. */
192 if (status)
193 error_counter++;
194
195 /* Unlisten on the server port. */
196 status = nx_tcp_server_socket_unlisten(&ip_0, 12);
197
198 /* Check for error. */
199 if (status)
200 error_counter++;
201
202 /* Delete the socket. */
203 status = nx_tcp_socket_delete(&server_socket);
204
205 /* Check for error. */
206 if(status)
207 error_counter++;
208 }
209
ntest_1_entry(ULONG thread_input)210 static void ntest_1_entry(ULONG thread_input)
211 {
212 UINT status;
213
214
215 /* Create a socket. */
216 status = nx_tcp_socket_create(&ip_1, &client_socket, "Client Socket",
217 NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 200,
218 NX_NULL, NX_NULL);
219
220 /* Check for error. */
221 if(status)
222 error_counter++;
223
224 /* Bind the socket. */
225 status = nx_tcp_client_socket_bind(&client_socket, 12, NX_IP_PERIODIC_RATE);
226
227 /* Check for error. */
228 if(status)
229 error_counter++;
230
231 /* Attempt to connect the socket. */
232 status = nx_tcp_client_socket_connect(&client_socket, IP_ADDRESS(1, 2, 3, 4), 12, 5 * NX_IP_PERIODIC_RATE);
233
234 /* Check for error. */
235 if(status)
236 error_counter++;
237
238 /* Let client check the ACK packet. */
239 ip_1.nx_ip_tcp_packet_receive = my_tcp_packet_receive_1_21_01_2;
240
241 /* Disconnect the client socket. */
242 status = nx_tcp_socket_disconnect(&client_socket, 2 * NX_IP_PERIODIC_RATE);
243
244 /* Check for error. */
245 if(status)
246 error_counter++;
247
248 /* Unbind the socket. */
249 status = nx_tcp_client_socket_unbind(&client_socket);
250
251 /* Check for error. */
252 if(status)
253 error_counter++;
254
255 /* Delete the socket. */
256 status = nx_tcp_socket_delete(&client_socket);
257
258 /* Check for error. */
259 if(status)
260 error_counter++;
261
262 /* Determine if the test was successful. */
263 if((error_counter) || (fin_counter != 1) || (ack_counter != 1))
264 {
265 printf("ERROR!\n");
266 test_control_return(1);
267 }
268 else
269 {
270 printf("SUCCESS!\n");
271 test_control_return(0);
272 }
273
274 }
275
ntest_0_connect_received(NX_TCP_SOCKET * socket_ptr,UINT port)276 static void ntest_0_connect_received(NX_TCP_SOCKET *socket_ptr, UINT port)
277 {
278
279 /* Check for the proper socket and port. */
280 if((socket_ptr != &server_socket) || (port != 12))
281 error_counter++;
282 }
283
ntest_0_disconnect_received(NX_TCP_SOCKET * socket)284 static void ntest_0_disconnect_received(NX_TCP_SOCKET *socket)
285 {
286
287 /* Check for proper disconnected socket. */
288 if(socket != &server_socket)
289 error_counter++;
290 }
291
my_packet_process_1_21_01(NX_IP * ip_ptr,NX_PACKET * packet_ptr,UINT * operation_ptr,UINT * delay_ptr)292 static UINT my_packet_process_1_21_01(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr)
293 {
294 NX_TCP_HEADER *tcp_header_ptr;
295
296 tcp_header_ptr = (NX_TCP_HEADER*)((packet_ptr -> nx_packet_prepend_ptr) + 20);
297 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
298
299 /* Check if it is a FIN packet. */
300 if((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT) && (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT))
301 {
302 /* Delay 1 second. */
303 *operation_ptr = NX_RAMDRIVER_OP_DELAY;
304 *delay_ptr = NX_IP_PERIODIC_RATE;
305
306 /* FIN packet has been processed. */
307 advanced_packet_process_callback = NX_NULL;
308 }
309 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
310
311 return NX_TRUE;
312 }
313
my_tcp_packet_receive_1_21_01(NX_IP * ip_ptr,NX_PACKET * packet_ptr)314 void my_tcp_packet_receive_1_21_01(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
315 {
316 NX_TCP_HEADER *tcp_header_ptr;
317
318 /* Check whether the state of server is in FIN_WAIT_1. */
319 if (server_socket.nx_tcp_socket_state == NX_TCP_FIN_WAIT_1)
320 {
321 tcp_header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
322 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
323
324 /* Check the packet is a FIN one. */
325 if(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT)
326 {
327 fin_counter++;
328
329 /* Deal packets with default routing. */
330 ip_0.nx_ip_tcp_packet_receive = _nx_tcp_packet_receive;
331 }
332
333 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
334 }
335
336 /* Let server receives the packet. */
337 _nx_tcp_packet_receive(ip_ptr, packet_ptr);
338 }
339
my_tcp_packet_receive_1_21_01_2(NX_IP * ip_ptr,NX_PACKET * packet_ptr)340 void my_tcp_packet_receive_1_21_01_2(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
341 {
342 NX_TCP_HEADER *tcp_header_ptr;
343
344 /* Check whether the packet is a ACK packet which responsing the FIN one. */
345 if(fin_counter == 1)
346 {
347 tcp_header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
348 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
349
350 if(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT)
351 {
352 ack_counter++;
353
354 /* Deal packets with default routing. */
355 ip_1.nx_ip_tcp_packet_receive = _nx_tcp_packet_receive;
356 }
357 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
358 }
359
360 /* Let client receive the packet. */
361 _nx_tcp_packet_receive(ip_ptr, packet_ptr);
362 }
363 #else
364
365 #ifdef CTEST
test_application_define(void * first_unused_memory)366 VOID test_application_define(void *first_unused_memory)
367 #else
368 void netx_1_21_01_application_define(void *first_unused_memory)
369 #endif
370 {
371
372 /* Print out test information banner. */
373 printf("NetX Test: TCP Spec 1.21.01 Test.....................................N/A\n");
374
375 test_control_return(3);
376 }
377 #endif
378