1 /* 12.21:TCP MUST be able to receive MSS option in SYN,ACK segment and calculate the effective send segment size appropriately.  */
2 
3 /*  Procedure
4     1.Connect
5     2.Client_socket's connect_MSS should equal server_socket's MSS.(client_socket's MSS = 1460, server_socket's MSS = 88)
6     3. A packet should be intercepted by function my_tcp_packet_receive_12_21 which is sent from client socket to server socket.
7     4. Check: the packet should be a SYN packet, increment the syn_counter. Whether or not calling the defaulted packet receiving function.
8     5. Check if all of the packets we catched can connected to the my_packet we send*/
9 
10 #include   "tx_api.h"
11 #include   "nx_api.h"
12 #include   "nx_tcp.h"
13 #if defined(__PRODUCT_NETXDUO__)
14 #include   "nx_ipv4.h"
15 #else
16 #include   "nx_ip.h"
17 #endif
18 #include   <time.h>
19 extern void    test_control_return(UINT status);
20 
21 #if !defined(NX_DISABLE_IPV4)
22 
23 #define     DEMO_STACK_SIZE    2048
24 
25 /* Define the counters used in the demo application...  */
26 
27 static TX_THREAD               ntest_0;
28 static TX_THREAD               ntest_1;
29 static NX_PACKET_POOL          pool_0;
30 static NX_IP                   ip_0;
31 static NX_IP                   ip_1;
32 static NX_TCP_SOCKET           client_socket;
33 static NX_TCP_SOCKET           server_socket;
34 
35 /* Define the counters used in the demo applicaton...  */
36 
37 static ULONG                   error_counter;
38 static ULONG                   syn_ack_counter;
39 static ULONG                   data_counter;
40 static ULONG                   mss_option_12_21;
41 static ULONG                   packet_length_12_21;
42 
43 static UCHAR                   callback_rcv_buffer[200];
44 static UINT                    callback_rcv_length;
45 static UCHAR                   rcv_buffer[200];
46 static UINT                    rcv_length;
47 static UCHAR                   data_12_21[200];
48 
49 /* Define thread prototypes.  */
50 
51 static void    ntest_0_entry(ULONG thread_input);
52 static void    ntest_1_entry(ULONG thread_input);
53 static void    ntest_1_connect_received(NX_TCP_SOCKET *server_socket, UINT port);
54 static void    ntest_1_disconnect_received(NX_TCP_SOCKET *server_socket);
55 static void    rand_12_21();
56 extern void    test_control_return(UINT status);
57 extern void    _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
58 extern void    _nx_ram_network_driver_1500(struct NX_IP_DRIVER_STRUCT *driver_req);
59 static void    my_tcp_packet_receive_12_21(NX_IP *ip_ptr, NX_PACKET *packet_ptr);
60 extern UINT    (*advanced_packet_process_callback)(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr);
61 static UINT    my_packet_process_12_21(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr);
62 
63 
64 /* Define what the initial system looks like.  */
65 
66 #ifdef CTEST
test_application_define(void * first_unused_memory)67 VOID test_application_define(void *first_unused_memory)
68 #else
69 void           netx_12_21_application_define(void *first_unused_memory)
70 #endif
71 {
72 CHAR       *pointer;
73 UINT       status;
74 
75     /* Setup the working pointer.  */
76     pointer = (CHAR *) first_unused_memory;
77 
78     error_counter = 0;
79     syn_ack_counter = 0;
80     data_counter = 0;
81     mss_option_12_21 = 0;
82     packet_length_12_21 = 200;
83     rcv_length = 0;
84     callback_rcv_length = 0;
85 
86     /* Create the main thread.  */
87     tx_thread_create(&ntest_0, "thread 0", ntest_0_entry, 0,
88                      pointer, DEMO_STACK_SIZE,
89                      4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
90 
91     pointer = pointer + DEMO_STACK_SIZE;
92 
93     /* Create the main thread.  */
94     tx_thread_create(&ntest_1, "thread 1", ntest_1_entry, 0,
95                      pointer, DEMO_STACK_SIZE,
96                      3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
97 
98     pointer = pointer + DEMO_STACK_SIZE;
99 
100     /* Initialize the NetX system.  */
101     nx_system_initialize();
102 
103     /* Create a packet pool.  */
104     status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 512, pointer, 8192);
105     pointer = pointer + 8192;
106 
107     if(status)
108         error_counter++;
109 
110     /* Create an IP instance.  */
111     status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver_1500,
112                           pointer, 2048, 1);
113     pointer = pointer + 2048;
114 
115     /* Create another IP instance.  */
116     status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
117                            pointer, 2048, 1);
118     pointer = pointer + 2048;
119 
120     if(status)
121         error_counter++;
122 
123     /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
124     status = nx_arp_enable(&ip_0, (void *) pointer, 1024);
125     pointer = pointer + 1024;
126 
127     /* Enable ARP and supply ARP cache memory for IP Instance 1.  */
128     status += nx_arp_enable(&ip_1, (void *) pointer, 1024);
129     pointer = pointer + 1024;
130 
131     /* Check ARP enable status.  */
132     if(status)
133         error_counter++;
134 
135     /* Enable TCP processing for both IP instances.  */
136     status = nx_tcp_enable(&ip_0);
137     status += nx_tcp_enable(&ip_1);
138 
139     /* Check TCP enable status.  */
140     if(status)
141         error_counter++;
142 }
143 
144 /* Define the test threads.  */
145 
ntest_0_entry(ULONG thread_input)146 static void    ntest_0_entry(ULONG thread_input)
147 {
148 UINT       status;
149 NX_PACKET  *my_packet;
150 
151 
152 
153     /* Print out test information banner.  */
154     printf("NetX Test:   TCP Spec 12.21 Test.......................................");
155 
156     /* Create a socket.  */
157     status = nx_tcp_socket_create(&ip_0, &client_socket, "Client Socket",
158                                   NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 300,
159                                   NX_NULL, NX_NULL);
160 
161 
162     /* Check for error.  */
163     if(status)
164         error_counter++;
165 
166     /* Bind the socket.  */
167     status = nx_tcp_client_socket_bind(&client_socket, 12, NX_IP_PERIODIC_RATE);
168 
169     /* Check for error.  */
170     if(status)
171         error_counter++;
172 
173     ip_0.nx_ip_tcp_packet_receive = my_tcp_packet_receive_12_21;
174 
175     status = nx_tcp_client_socket_connect(&client_socket, IP_ADDRESS(1, 2, 3, 5), 12, 5 * NX_IP_PERIODIC_RATE);
176 
177     /* Check for error.  */
178     if(status)
179         error_counter++;
180 
181     /*Check if the MSS option of server socket has calculated to the appropriate 88(server_socket's MSS) which the SYN,ACK packet from client socket carried*/
182     if(client_socket.nx_tcp_socket_connect_mss != mss_option_12_21)
183         error_counter++;
184 
185     advanced_packet_process_callback = my_packet_process_12_21;
186 
187     /* Allocate a packet.  */
188     status =  nx_packet_allocate(&pool_0, &my_packet, NX_TCP_PACKET, NX_IP_PERIODIC_RATE);
189 
190     /* Check status.  */
191     if (status)
192         error_counter++;
193 
194     /* Create a 200-byte length message randomly. */
195     rand_12_21();
196 
197     /* Fill in the packet with data.     */
198     status = nx_packet_data_append(my_packet, data_12_21, packet_length_12_21, &pool_0, NX_IP_PERIODIC_RATE);
199 
200     /* Check status.  */
201     if(status)
202         error_counter++;
203 
204     /* Send the packet out!  */
205     status =  nx_tcp_socket_send(&client_socket, my_packet, 5 * NX_IP_PERIODIC_RATE);
206 
207     /* Check for error.  */
208     if (status)
209         error_counter++;
210 
211 
212     /* Disconnect this socket.  */
213     status = nx_tcp_socket_disconnect(&client_socket, NX_IP_PERIODIC_RATE);
214 
215     /* Check for error.  */
216     if(status)
217         error_counter++;
218 
219     /*Check if the content of the callback_rcv_buffer which appended by all the received packets' payload is the data_12_18 sent before*/
220     if(!memcmp(callback_rcv_buffer, data_12_21, packet_length_12_21))
221         data_counter++;
222 
223     /* Unbind the socket.  */
224     status = nx_tcp_client_socket_unbind(&client_socket);
225 
226     /* Check for error.  */
227     if(status)
228         error_counter++;
229 
230     status += nx_tcp_socket_delete(&client_socket);
231 
232     /* Check for error.  */
233     if(status)
234         error_counter++;
235 
236 
237     /* Check for error.  */
238     if((error_counter !=0) || (syn_ack_counter != 1) || (data_counter != 2))
239     {
240         printf("ERROR\n");
241         test_control_return(1);
242     }
243     else
244     {
245         printf("SUCCESS!\n");
246         test_control_return(0);
247     }
248 }
249 
ntest_1_entry(ULONG thread_input)250 static void    ntest_1_entry(ULONG thread_input)
251 {
252 UINT       status;
253 ULONG      actual_status;
254 NX_PACKET  *my_packet;
255 ULONG      bytes_copied;
256 
257     /* Ensure the IP instance has been initialized.  */
258     status = nx_ip_status_check(&ip_1, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE);
259 
260     /* Check for error.  */
261     if(status)
262         error_counter++;
263 
264     /* Create a socket.  */
265     status = nx_tcp_socket_create(&ip_1, &server_socket, "Server Socket",
266                                   NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 200,
267                                   NX_NULL, ntest_1_disconnect_received);
268 
269     /* Check for error.  */
270     if(status)
271         error_counter++;
272 
273     /* Setup this thread to listen.  */
274     status = nx_tcp_server_socket_listen(&ip_1, 12, &server_socket, 5, ntest_1_connect_received);
275 
276     /* Check for error.  */
277     if(status)
278         error_counter++;
279 
280     /* Accept a client socket connection.  */
281     status = nx_tcp_server_socket_accept(&server_socket, NX_IP_PERIODIC_RATE);
282 
283     /* Check for error.  */
284     if(status)
285         error_counter++;
286 
287     while(!(nx_tcp_socket_receive(&server_socket, &my_packet, NX_IP_PERIODIC_RATE)))
288     {
289         /*Check if the packet is fragmented by TCP layer.*/
290         if(my_packet -> nx_packet_length > mss_option_12_21)
291             error_counter++;
292 
293         /* Retrieve data from packet to the receive buffer. */
294         status = nx_packet_data_retrieve(my_packet, &rcv_buffer[rcv_length], &bytes_copied);
295         if(status)
296             error_counter++;
297 
298         rcv_length += bytes_copied;
299     }
300 
301     /*Check if the content which connected by all the received packets is the data_12_21 sent from the client socket*/
302     if(!memcmp(rcv_buffer, data_12_21, packet_length_12_21))
303         data_counter++;
304 
305     /* Disconnect the server socket.  */
306     status = nx_tcp_socket_disconnect(&server_socket, NX_IP_PERIODIC_RATE);
307 
308     /* Check for error.  */
309     if (status)
310         error_counter++;
311 
312     /* Unaccept the server socket.  */
313     status = nx_tcp_server_socket_unaccept(&server_socket);
314 
315     /* Check for error.  */
316     if (status)
317         error_counter++;
318 
319     /* Unlisten on the server port.  */
320     status =  nx_tcp_server_socket_unlisten(&ip_1, 12);
321 
322     /* Check for error.  */
323     if (status)
324         error_counter++;
325 
326     /* Delete the socket.  */
327     status = nx_tcp_socket_delete(&server_socket);
328 
329     /* Check for error.  */
330     if(status)
331         error_counter++;
332 
333 
334 }
335 
ntest_1_connect_received(NX_TCP_SOCKET * socket_ptr,UINT port)336 static void    ntest_1_connect_received(NX_TCP_SOCKET *socket_ptr, UINT port)
337 {
338 
339     /* Check for the proper socket and port.  */
340     if((socket_ptr != &server_socket) || (port != 12))
341         error_counter++;
342 }
343 
ntest_1_disconnect_received(NX_TCP_SOCKET * socket)344 static void    ntest_1_disconnect_received(NX_TCP_SOCKET *socket)
345 {
346 
347     /* Check for proper disconnected socket.  */
348     if(socket != &server_socket)
349         error_counter++;
350 }
351 
rand_12_21()352 static void rand_12_21()
353 {
354 UINT       flag;
355 UINT       j, k = 0;
356 
357     srand((unsigned)time(NULL));
358     for(j = 0;j < 200;j++)
359     {
360         flag = rand() & 1;
361         if(flag)
362             data_12_21[k++] = 'A' + rand() % 26;
363         else
364             data_12_21[k++] = 'a' + rand() % 26;
365     }
366 }
367 
368 
my_packet_process_12_21(NX_IP * ip_ptr,NX_PACKET * packet_ptr,UINT * operation_ptr,UINT * delay_ptr)369 static UINT    my_packet_process_12_21(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT *operation_ptr, UINT *delay_ptr)
370 {
371 #if defined(__PRODUCT_NETXDUO__)
372 NX_IPV4_HEADER    *ip_header_ptr = (NX_IPV4_HEADER*)(packet_ptr -> nx_packet_prepend_ptr);
373 #else
374 NX_IP_HEADER    *ip_header_ptr = (NX_IP_HEADER*)(packet_ptr -> nx_packet_prepend_ptr);
375 #endif
376 
377     if((packet_ptr -> nx_packet_length) > 40)
378     {
379         NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
380 
381         /*Check if the packet is fragmented by IP layer.*/
382         if(!(ip_header_ptr->nx_ip_header_word_1& NX_IP_FRAGMENT_MASK))
383         {
384             /*Check if the packet is fragmented by TCP layer*/
385             if((packet_ptr->nx_packet_length - 40) > mss_option_12_21)
386                 error_counter++;
387         }
388         else
389             error_counter++;
390 
391         /* Append the intercepted packet's content to the receive buffer. */
392         memcpy(&callback_rcv_buffer[callback_rcv_length], packet_ptr->nx_packet_prepend_ptr + 40, packet_ptr -> nx_packet_length - 40);
393         callback_rcv_length = callback_rcv_length + packet_ptr -> nx_packet_length - 40;
394 
395         NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
396     }
397 
398     return NX_TRUE;
399 }
400 
my_tcp_packet_receive_12_21(NX_IP * ip_ptr,NX_PACKET * packet_ptr)401 static void    my_tcp_packet_receive_12_21(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
402 {
403 NX_TCP_HEADER  *header_ptr;
404 ULONG           option_words;
405 
406     header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
407     NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_3);
408 
409     /* Client receives a SYN+ACK packet.  */
410     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))
411     {
412         /* It is a SYN+ACK packet.  */
413         syn_ack_counter++;
414 
415         /*Get the MSS option kind*/
416         option_words =  (header_ptr -> nx_tcp_header_word_3 >> 28) - 5;
417 
418         /*Get the MSS option form the SYN packet.*/
419         _nx_tcp_mss_option_get((packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER)), option_words*sizeof(ULONG), &mss_option_12_21);
420 
421         ip_0.nx_ip_tcp_packet_receive = _nx_tcp_packet_receive;
422     }
423 
424     NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_3);
425 
426     _nx_tcp_packet_receive(ip_ptr, packet_ptr);
427 
428 }
429 #else
430 
431 #ifdef CTEST
test_application_define(void * first_unused_memory)432 VOID test_application_define(void *first_unused_memory)
433 #else
434 void    netx_12_21_application_define(void *first_unused_memory)
435 #endif
436 {
437 
438     /* Print out test information banner.  */
439     printf("NetX Test:   TCP Spec 12.21 Test.......................................N/A\n");
440 
441     test_control_return(3);
442 }
443 #endif