1 /* This NetX test concentrates on the ICMPv4 Error Message.  */
2 
3 #include   "tx_api.h"
4 #include   "nx_api.h"
5 #include   "nx_ip.h"
6 #include   "nx_icmp.h"
7 
8 #if defined (__PRODUCT_NETXDUO__) && !defined (NX_DISABLE_ICMPV4_ERROR_MESSAGE) && !defined(NX_DISABLE_IPV4)
9 
10 #define     DEMO_STACK_SIZE         2048
11 
12 
13 /* Define the ThreadX and NetX object control blocks...  */
14 
15 static TX_THREAD               ntest_0;
16 
17 static NX_PACKET_POOL          pool_0;
18 static NX_IP                   ip_0;
19 static NX_IP                   ip_1;
20 
21 
22 
23 /* Define the counters used in the test application...  */
24 
25 static ULONG                   error_counter;
26 static ULONG                   ip_0_icmp_counter;
27 static ULONG                   ip_1_icmp_counter;
28 static ULONG                   ip_1_icmp_error_message_counter;
29 
30 
31 /* Define thread prototypes.  */
32 
33 static void    ntest_0_entry(ULONG thread_input);
34 extern void    test_control_return(UINT status);
35 extern void    _nx_ram_network_driver_256(struct NX_IP_DRIVER_STRUCT *driver_req);
36 extern UINT   (*packet_process_callback)(NX_IP *ip_ptr, NX_PACKET *packet_ptr);
37 static UINT   my_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr);
38 static VOID   my_ipv4_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr);
39 
40 
41 /* Define what the initial system looks like.  */
42 
43 #ifdef CTEST
test_application_define(void * first_unused_memory)44 VOID test_application_define(void *first_unused_memory)
45 #else
46 void    netx_icmp_send_error_message_test_application_define(void *first_unused_memory)
47 #endif
48 {
49 
50 CHAR    *pointer;
51 UINT    status;
52 
53 
54     /* Setup the working pointer.  */
55     pointer =  (CHAR *) first_unused_memory;
56 
57     /* Initialize the value.  */
58     error_counter = 0;
59     ip_0_icmp_counter = 0;
60     ip_1_icmp_counter = 0;
61     ip_1_icmp_error_message_counter = 0;
62 
63     /* Create the main thread.  */
64     tx_thread_create(&ntest_0, "thread 0", ntest_0_entry, 0,
65             pointer, DEMO_STACK_SIZE,
66             4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
67     pointer =  pointer + DEMO_STACK_SIZE;
68 
69     /* Initialize the NetX system.  */
70     nx_system_initialize();
71 
72     /* Create a packet pool.  */
73     status =  nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 256, pointer, 2048);
74     pointer = pointer + 2048;
75 
76     if (status)
77         error_counter++;
78 
79     /* Create an IP instance.  */
80     status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver_256,
81                     pointer, 2048, 1);
82     pointer =  pointer + 2048;
83 
84     /* Create another IP instance.  */
85     status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver_256,
86                     pointer, 2048, 2);
87     pointer =  pointer + 2048;
88     if (status)
89         error_counter++;
90 
91     /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
92     status =  nx_arp_enable(&ip_0, (void *) pointer, 1024);
93     pointer = pointer + 1024;
94     if (status)
95         error_counter++;
96 
97     /* Enable ARP and supply ARP cache memory for IP Instance 1.  */
98     status  =  nx_arp_enable(&ip_1, (void *) pointer, 1024);
99     pointer = pointer + 1024;
100     if (status)
101         error_counter++;
102 
103     /* Enable ICMP processing for IP 0 instances.  */
104     status =  nx_icmp_enable(&ip_0);
105 
106     /* Check TCP enable status.  */
107     if (status)
108         error_counter++;
109 }
110 
111 
112 
113 /* Define the test threads.  */
114 
ntest_0_entry(ULONG thread_input)115 static void    ntest_0_entry(ULONG thread_input)
116 {
117 
118 UINT        status;
119 NX_PACKET   *my_packet;
120 
121 
122     /* Print out test information banner.  */
123     printf("NetX Test:   ICMP Send Error Message Test..............................");
124 
125     /* Check for earlier error.  */
126     if (error_counter)
127     {
128 
129         printf("ERROR!\n");
130         test_control_return(1);
131     }
132 
133     packet_process_callback = my_packet_process;
134 
135     /*  Test illegal length of NX_IP_OPTION_INTERNET_TIMESTAMP option by ping.  */
136     status = nx_icmp_ping(&ip_0, IP_ADDRESS(1, 2, 3, 5), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 28, &my_packet, 1 * NX_IP_PERIODIC_RATE);
137 
138     /* Check the status.  */
139     if ((status != NX_NO_RESPONSE) || (my_packet))
140     {
141 
142         printf("ERROR!\n");
143         test_control_return(1);
144     }
145 
146     /* Check the value.  */
147     if ((ip_0_icmp_counter != 1) && (ip_1_icmp_counter != 0))
148     {
149 
150         printf("ERROR!\n");
151         test_control_return(1);
152     }
153 
154     /* Enable ICMP processing for IP 1 instances.  */
155     status = nx_icmp_enable(&ip_1);
156 
157     /* Check TCP enable status.  */
158     if (status)
159         error_counter++;
160 
161     /*  Test illegal length of NX_IP_OPTION_INTERNET_TIMESTAMP option and destination address (255, 255, 255, 255) by ping.  */
162     status = nx_icmp_ping(&ip_0, IP_ADDRESS(1, 2, 3, 5), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 28, &my_packet, 1 * NX_IP_PERIODIC_RATE);
163 
164     /* Check the status.  */
165     if ((status != NX_NO_RESPONSE) || (my_packet))
166     {
167 
168         printf("ERROR!\n");
169         test_control_return(1);
170     }
171 
172     /* Check the value.  */
173     if ((ip_0_icmp_counter != 2) && (ip_1_icmp_counter != 0))
174     {
175 
176         printf("ERROR!\n");
177         test_control_return(1);
178     }
179 
180     /*  Test illegal length of NX_IP_OPTION_INTERNET_TIMESTAMP option and non-initial fragment by ping.  */
181     status = nx_icmp_ping(&ip_0, IP_ADDRESS(1, 2, 3, 5), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 28, &my_packet, 1 * NX_IP_PERIODIC_RATE);
182 
183     /* Check the status.  */
184     if ((status != NX_NO_RESPONSE) || (my_packet))
185     {
186 
187         printf("ERROR!\n");
188         test_control_return(1);
189     }
190 
191     /* Check the value.  */
192     if ((ip_0_icmp_counter != 3) && (ip_1_icmp_counter != 0))
193     {
194 
195         printf("ERROR!\n");
196         test_control_return(1);
197     }
198 
199     /* Set my function.  */
200     ip_1.nx_ipv4_packet_receive = my_ipv4_packet_receive;
201 
202     /*  Test illegal length of NX_IP_OPTION_INTERNET_TIMESTAMP option by ping.  */
203     status = nx_icmp_ping(&ip_0, IP_ADDRESS(1, 2, 3, 5), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 28, &my_packet, 1 * NX_IP_PERIODIC_RATE);
204 
205     /* Check the status.  */
206     if ((status != NX_NO_RESPONSE) || (my_packet))
207     {
208 
209         printf("ERROR!\n");
210         test_control_return(1);
211     }
212 
213     /* Check the value.  */
214     if ((ip_0_icmp_counter != 4) && (ip_1_icmp_counter != 0))
215     {
216 
217         printf("ERROR!\n");
218         test_control_return(1);
219     }
220 
221 #ifndef NX_ENABLE_SOURCE_ADDRESS_CHECK
222     /*  Test illegal length of NX_IP_OPTION_INTERNET_TIMESTAMP option and multicast address by ping.  */
223     status = nx_icmp_ping(&ip_0, IP_ADDRESS(1, 2, 3, 5), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 28, &my_packet, 1 * NX_IP_PERIODIC_RATE);
224 
225     /* Check the status.  */
226     if ((status != NX_NO_RESPONSE) || (my_packet))
227     {
228 
229         printf("ERROR!\n");
230         test_control_return(1);
231     }
232 
233     /* Check the value.  */
234     if ((ip_0_icmp_counter != 5) && (ip_1_icmp_counter != 0))
235     {
236 
237         printf("ERROR!\n");
238         test_control_return(1);
239     }
240 #endif
241 
242     /*  Test unknown protocol.  */
243     status = nx_icmp_ping(&ip_0, IP_ADDRESS(1, 2, 3, 5), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 28, &my_packet, 1 * NX_IP_PERIODIC_RATE);
244 
245     /* Check the status.  */
246     if ((status != NX_NO_RESPONSE) || (my_packet))
247     {
248 
249         printf("ERROR!\n");
250         test_control_return(1);
251     }
252 
253 #ifndef NX_ENABLE_SOURCE_ADDRESS_CHECK
254     /* Check the value.  */
255     if ((ip_0_icmp_counter != 6) && (ip_1_icmp_counter != 1))
256 #else
257     /* Check the value.  */
258     if ((ip_0_icmp_counter != 5) && (ip_1_icmp_counter != 1))
259 #endif
260     {
261 
262         printf("ERROR!\n");
263         test_control_return(1);
264     }
265 
266     printf("SUCCESS!\n");
267     test_control_return(0);
268 }
269 
my_packet_process(NX_IP * ip_ptr,NX_PACKET * packet_ptr)270 static UINT   my_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
271 {
272 
273 NX_IPV4_HEADER   *ip_header_ptr;
274 NX_ICMP_HEADER   *icmp_header_ptr;
275 ULONG            ip_header_length;
276 ULONG            protocol;
277 ULONG            checksum;
278 ULONG            val;
279 ULONG            offset = 0;
280 ULONG            shift;
281 ULONG            message_word;
282 
283     /* Get the IP header pointer.  */
284     ip_header_ptr = (NX_IPV4_HEADER*)(packet_ptr -> nx_packet_prepend_ptr);
285 
286     /* Get IP header. */
287     NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2);
288     protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF;
289     NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2);
290 
291     /* Only process ICMP message.  */
292     if (protocol != NX_PROTOCOL_ICMP)
293         return (NX_TRUE);
294 
295     /* Modify the ICMP packet from ip_0 instance. */
296     if(ip_ptr == &ip_0)
297     {
298 
299         /* Update the icmp_counter.  */
300         ip_0_icmp_counter++;
301 
302         /* Get the IP header pointer.  */
303         ip_header_ptr = (NX_IPV4_HEADER*)(packet_ptr -> nx_packet_prepend_ptr);
304 
305         /* Calculate the IPv4 option length.  */
306         NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0);
307         ip_header_length = ((ip_header_ptr -> nx_ip_header_word_0 & NX_IP_LENGTH_MASK) >> 24) * sizeof(ULONG);
308 
309         /* Get ICMP header. */
310         icmp_header_ptr = (NX_ICMP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr + ip_header_length);
311 
312         /* Add the illegal length 7 for NX_IP_OPTION_INTERNET_TIMESTAMP option.  */
313         if ((ip_0_icmp_counter == 1) || (ip_0_icmp_counter == 2) ||
314 #ifndef NX_ENABLE_SOURCE_ADDRESS_CHECK
315             (ip_0_icmp_counter == 3) || (ip_0_icmp_counter == 4) || (ip_0_icmp_counter == 5))
316 #else
317             (ip_0_icmp_counter == 3) || (ip_0_icmp_counter == 4))
318 #endif
319         {
320 
321             /* Move the data to add the option. */
322             offset = 12;
323             shift = packet_ptr -> nx_packet_length - ip_header_length;
324             memmove(((UCHAR *)(icmp_header_ptr)) + offset, icmp_header_ptr, shift);
325 
326             /* Clear memory.  */
327             memset(&message_word, 0, sizeof(ULONG));
328 
329             /* Add type, length, offset, overflw and flags.  */
330             message_word = (ULONG)((NX_IP_OPTION_INTERNET_TIMESTAMP << 24) | (7 << 16) | (5 << 8) );
331 
332             /* Adjust for endianness. */
333             NX_CHANGE_ULONG_ENDIAN(message_word);
334 
335             /* Add type, length, offset, overflw and flags.  */
336             memcpy(icmp_header_ptr, &message_word, sizeof(ULONG));
337 
338             /* Clear the time stamp value.  */
339             memset(((UCHAR *)(icmp_header_ptr)) + sizeof(ULONG), 0 , offset - sizeof(ULONG));
340         }
341 
342         /* Modified the destination address to 255.255.255.255.  */
343         if (ip_0_icmp_counter == 2)
344         {
345 
346             /* Modified the destination address to 255.255.255.255.  */
347             NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
348             ip_header_ptr -> nx_ip_header_destination_ip = IP_ADDRESS(255, 255, 255, 255);
349             NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
350         }
351 
352         /* Modified the fragment offset.  */
353         if (ip_0_icmp_counter == 3)
354         {
355 
356             /* Modified the destination address to 255.255.255.255.  */
357             NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
358             ip_header_ptr -> nx_ip_header_word_1 |= 10;
359             NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
360         }
361 
362 #ifndef NX_ENABLE_SOURCE_ADDRESS_CHECK
363         /* Modified the destination address to 255.255.255.255.  */
364         if (ip_0_icmp_counter == 5)
365         {
366 
367             /* Modified the source address to 224.0.0.251.  */
368             NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip);
369             ip_header_ptr -> nx_ip_header_source_ip = IP_ADDRESS(224,0,0,251);
370             NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip);
371         }
372 #endif
373 
374         /* Modified the protocol as unknown.  */
375 #ifndef NX_ENABLE_SOURCE_ADDRESS_CHECK
376         if (ip_0_icmp_counter == 6)
377 #else
378         if (ip_0_icmp_counter == 5)
379 #endif
380         {
381 
382             /* Set the protocol as unkown protocol, ip_1 should send the icmp unreachable meesage.  */;
383             NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2);
384             ip_header_ptr -> nx_ip_header_word_2 |= 0x00FF0000;
385             NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2);
386         }
387 
388         /* Update the header IP length and total length.  */
389         ip_header_length += offset;
390         packet_ptr -> nx_packet_append_ptr += offset;
391         packet_ptr -> nx_packet_length += offset;
392 
393         /* Rebuild the first 32-bit word of the IP header.  */
394         ip_header_ptr -> nx_ip_header_word_0 =  (ULONG)((NX_IP_VERSION_V4 << 28) |
395                                                         ((ip_header_length/sizeof(ULONG)) << 24) |
396                                                         NX_IP_NORMAL |
397                                                         (0xFFFF & packet_ptr -> nx_packet_length));
398 
399         /* Endian swapping logic.  */
400         NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0);
401 
402         /* Clear the checksum . */
403         ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 & 0x0000FFFF;
404 
405         /* Calculate the checksum.  */
406         checksum = _nx_ip_checksum_compute(packet_ptr, NX_IP_VERSION_V4,
407                                            /* Length is the size of IP header, including options */
408                                            (UINT)(ip_header_length),
409                                            /* IPv4 header checksum does not use src/dest addresses */
410                                            NULL, NULL);
411 
412         val = (ULONG)(~checksum);
413         val = val & NX_LOWER_16_MASK;
414 
415         /* Convert to network byte order. */
416         NX_CHANGE_ULONG_ENDIAN(val);
417 
418         /* Now store the checksum in the IP header.  */
419         ip_header_ptr -> nx_ip_header_word_2 =  ip_header_ptr -> nx_ip_header_word_2 | val;
420     }
421 
422     /* Check the ICMP packet from ip_1 instance. */
423     if(ip_ptr == &ip_1)
424     {
425 
426         /* Update the icmp_counter.  */
427         ip_1_icmp_counter++;
428     }
429 
430     return NX_TRUE;
431 }
432 
my_ipv4_packet_receive(NX_IP * ip_ptr,NX_PACKET * packet_ptr)433 VOID  my_ipv4_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
434 {
435 NX_PACKET   *my_packet[20];
436 UINT        packet_counter;
437 UINT        i;
438 
439     /* Record the counter.  */
440     packet_counter = ip_ptr -> nx_ip_default_packet_pool -> nx_packet_pool_available;
441 
442     /* Loop to allocate the packet.  */
443     for (i = 0; i < packet_counter; i ++)
444         nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &my_packet[i], 0, NX_NO_WAIT);
445 
446     /* Receive the packet.  */
447     _nx_ipv4_packet_receive(ip_ptr, packet_ptr);
448 
449     /* Loop to release the packet.  */
450     for (i = packet_counter; i > 0; i --)
451         nx_packet_release(my_packet[i - 1]);
452 
453     /* Reset the function.  */
454     ip_1.nx_ipv4_packet_receive = _nx_ipv4_packet_receive;
455 }
456 
457 #else
458 
459 extern void    test_control_return(UINT status);
460 
461 #ifdef CTEST
test_application_define(void * first_unused_memory)462 VOID test_application_define(void *first_unused_memory)
463 #else
464 void    netx_icmp_send_error_message_test_application_define(void *first_unused_memory)
465 #endif
466 {
467     printf("NetX Test:   ICMP Send Error Message Test..............................N/A\n");
468     test_control_return(3);
469 }
470 #endif
471