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