1 /* This is a small demo of the NetX Duo DHCPv6 Client and Server for the high-performance
2    NetX Duo stack.  */
3 
4 #include    <stdio.h>
5 #include   "tx_api.h"
6 #include   "nx_api.h"
7 extern void test_control_return(UINT status);
8 
9 #if defined(FEATURE_NX_IPV6) && !defined(NX_DISABLE_FRAGMENTATION)
10 #include   "nxd_dhcpv6_client.h"
11 #include   "nxd_dhcpv6_server.h"
12 
13 #define     DEMO_STACK_SIZE                     2048
14 #define     NX_DHCPV6_THREAD_STACK_SIZE         2048
15 #define     NX_PACKET_SIZE                      1536
16 #define     NX_PACKET_POOL_SIZE                 (NX_PACKET_SIZE * 8)
17 
18 /* Define the ThreadX and NetX object control blocks...  */
19 
20 static NX_PACKET_POOL          pool_0;
21 static TX_THREAD               thread_client;
22 static TX_THREAD               thread_server;
23 static NX_IP                   client_ip;
24 static NX_IP                   server_ip;
25 
26 /* Define the Client and Server instances. */
27 
28 static NX_DHCPV6               dhcp_client;
29 static NX_DHCPV6_SERVER        dhcp_server;
30 
31 /* Define the error counter used in the demo application...  */
32 static ULONG                   error_counter;
33 static CHAR                    *pointer;
34 
35 static NXD_ADDRESS             server_address;
36 static NXD_ADDRESS             dns_ipv6_address;
37 static NXD_ADDRESS             start_ipv6_address;
38 static NXD_ADDRESS             end_ipv6_address;
39 
40 
41 /* Define thread prototypes.  */
42 
43 static void    thread_client_entry(ULONG thread_input);
44 static void    thread_server_entry(ULONG thread_input);
45 extern void    _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);
46 
47 
48 /* Define some DHCPv6 parameters.  */
49 
50 #define DHCPV6_IANA_ID                  0xC0DEDBAD
51 #define DHCPV6_T1                       NX_DHCPV6_INFINITE_LEASE
52 #define DHCPV6_T2                       NX_DHCPV6_INFINITE_LEASE
53 #define NX_DHCPV6_REFERRED_LIFETIME     NX_DHCPV6_INFINITE_LEASE
54 #define NX_DHCPV6_VALID_LIFETIME        NX_DHCPV6_INFINITE_LEASE
55 
56 
57 /* Define what the initial system looks like.  */
58 
59 #ifdef CTEST
test_application_define(void * first_unused_memory)60 VOID test_application_define(void *first_unused_memory)
61 #else
62 void    netx_dhcpv6_basic_test_application_define(void *first_unused_memory)
63 #endif
64 {
65 
66 UINT    status;
67 
68     /* Setup the working pointer.  */
69     pointer =  (CHAR *) first_unused_memory;
70 
71     /* Initialize the NetX system.  */
72     nx_system_initialize();
73 
74     /* Create the Client thread.  */
75     status = tx_thread_create(&thread_client, "Client thread", thread_client_entry, 0,
76                               pointer, DEMO_STACK_SIZE,
77                               4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
78 
79     pointer =  pointer + DEMO_STACK_SIZE;
80 
81     /* Check for IP create errors.  */
82     if (status)
83     {
84         error_counter++;
85     }
86 
87     /* Create the Server thread.  */
88     status = tx_thread_create(&thread_server, "Server thread", thread_server_entry, 0,
89                               pointer, DEMO_STACK_SIZE,
90                               3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
91     pointer =  pointer + DEMO_STACK_SIZE;
92 
93     /* Check for IP create errors.  */
94     if (status)
95     {
96         error_counter++;
97     }
98 
99     /* Create a packet pool.  */
100     status =  nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 1024, pointer, NX_PACKET_POOL_SIZE);
101     pointer = pointer + NX_PACKET_POOL_SIZE;
102 
103     /* Check for pool creation error.  */
104     if (status)
105         error_counter++;
106 
107     /* Create a Client IP instance.  */
108     status = nx_ip_create(&client_ip, "Client IP", IP_ADDRESS(0, 0, 0, 0),
109                           0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
110                           pointer, 2048, 1);
111 
112     pointer =  pointer + 2048;
113 
114     /* Check for IP create errors.  */
115     if (status)
116     {
117         error_counter++;
118     }
119 
120     /* Create a Server IP instance.  */
121     status = nx_ip_create(&server_ip, "Server IP", IP_ADDRESS(1, 2, 3, 4),
122                           0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
123                           pointer, 2048, 1);
124 
125     pointer =  pointer + 2048;
126 
127     /* Check for IP create errors.  */
128     if (status)
129     {
130         error_counter++;
131     }
132 
133     /* Enable UDP traffic for sending DHCPv6 messages.  */
134     status =  nx_udp_enable(&client_ip);
135     status +=  nx_udp_enable(&server_ip);
136 
137     /* Check for UDP enable errors.  */
138     if (status)
139     {
140         error_counter++;
141     }
142 
143     /* Enable the IPv6 services. */
144     status = nxd_ipv6_enable(&client_ip);
145     status += nxd_ipv6_enable(&server_ip);
146 
147     /* Check for IPv6 enable errors.  */
148     if (status)
149     {
150         error_counter++;
151     }
152 
153     /* Enable the ICMPv6 services. */
154     status = nxd_icmp_enable(&client_ip);
155     status += nxd_icmp_enable(&server_ip);
156 
157     /* Check for ICMP enable errors.  */
158     if (status)
159     {
160         error_counter++;
161     }
162 
163     /* Enable the fragment feature.  */
164     status = nx_ip_fragment_enable(&client_ip);
165     status += nx_ip_fragment_enable(&server_ip);
166 
167     /* Check for ICMP enable errors.  */
168     if (status)
169     {
170         error_counter++;
171     }
172 }
173 
174 /* Define the Client host application thread. */
175 
thread_client_entry(ULONG thread_input)176 void    thread_client_entry(ULONG thread_input)
177 {
178 
179 UINT        status;
180 NXD_ADDRESS ipv6_address;
181 NXD_ADDRESS dns_address;
182 ULONG       prefix_length;
183 UINT        interface_index;
184 ULONG       T1, T2, preferred_lifetime, valid_lifetime;
185 UINT        address_count;
186 UINT        address_index;
187 NX_PACKET   *my_packet;
188 
189 
190     /* Print out test information banner.  */
191     printf("NetX Test:   DHCPv6 Basic Test.........................................");
192 
193     /* Check for earlier error.  */
194     if(error_counter)
195     {
196         printf("ERROR!\n");
197         test_control_return(1);
198     }
199 
200     /* Establish the link local address for the host. The RAM driver creates
201        a virtual MAC address of 0x1122334456. */
202     status = nxd_ipv6_address_set(&client_ip, 0, NX_NULL, 10, NULL);
203 
204     /* Let NetX Duo and the network driver get initialized. Also give the server time to get set up. */
205     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
206 
207     /* Create the DHCPv6 Client. */
208     status =  nx_dhcpv6_client_create(&dhcp_client, &client_ip, "DHCPv6 Client", &pool_0, pointer, NX_DHCPV6_THREAD_STACK_SIZE,
209                                       NX_NULL, NX_NULL);
210     pointer = pointer + NX_DHCPV6_THREAD_STACK_SIZE;
211 
212     /* Check for errors.  */
213     if(status)
214     {
215         printf("ERROR!\n");
216         test_control_return(1);
217     }
218 
219     /* Create a Link Layer Plus Time DUID for the DHCPv6 Client. Set time ID field
220        to NULL; the DHCPv6 Client API will supply one. */
221     status = nx_dhcpv6_create_client_duid(&dhcp_client, NX_DHCPV6_DUID_TYPE_LINK_TIME,
222                                           NX_DHCPV6_HW_TYPE_IEEE_802, 0);
223 
224     /* Check for errors.  */
225     if(status)
226     {
227         printf("ERROR!\n");
228         test_control_return(1);
229     }
230 
231     /* Create the DHCPv6 client's Identity Association (IA-NA) now.
232 
233        Note that if this host had already been assigned in IPv6 lease, it
234        would have to use the assigned T1 and T2 values in loading the DHCPv6
235        client with an IANA block.
236     */
237     status = nx_dhcpv6_create_client_iana(&dhcp_client, DHCPV6_IANA_ID, DHCPV6_T1,  DHCPV6_T2);
238 
239     /* Check for errors.  */
240     if(status)
241     {
242         printf("ERROR!\n");
243         test_control_return(1);
244     }
245 
246     /* Starting up the NetX DHCPv6 Client. */
247     status =  nx_dhcpv6_start(&dhcp_client);
248 
249     /* Check for errors.  */
250     if(status)
251     {
252         printf("ERROR!\n");
253         test_control_return(1);
254     }
255 
256     /* If the host also want to get the option message, set the list of desired options to enabled. */
257     nx_dhcpv6_request_option_timezone(&dhcp_client, NX_TRUE);
258     nx_dhcpv6_request_option_DNS_server(&dhcp_client, NX_TRUE);
259     nx_dhcpv6_request_option_time_server(&dhcp_client, NX_TRUE);
260     nx_dhcpv6_request_option_domain_name(&dhcp_client, NX_TRUE);
261 
262     /* Now, the host send the solicit message to get the IPv6 address and other options from the DHCPv6 server. */
263     status = nx_dhcpv6_request_solicit(&dhcp_client);
264 
265     /* Check for errors.  */
266     if(status)
267     {
268         printf("ERROR!\n");
269         test_control_return(1);
270     }
271 
272     /* Waiting for get the IPv6 address and do the duplicate address detection. */
273     tx_thread_sleep(6 * NX_IP_PERIODIC_RATE);
274 
275     /* Get the valid IPv6 address count which the DHCPv6 server assigned .  */
276     status = nx_dhcpv6_get_valid_ip_address_count(&dhcp_client, &address_count);
277 
278     /* Check for errors.  */
279     if ((status) || (address_count != 1))
280     {
281         printf("ERROR!\n");
282         test_control_return(1);
283     }
284 
285     /* Get the IPv6 address, preferred lifetime and valid lifetime according to the address index. */
286     address_index = 0;
287     status = nx_dhcpv6_get_valid_ip_address_lease_time(&dhcp_client, address_index, &ipv6_address, &preferred_lifetime, &valid_lifetime);
288 
289     /* Check for errors.  */
290     if ((status) || (address_count != 1))
291     {
292         printf("ERROR!\n");
293         test_control_return(1);
294     }
295 
296     /* Get the IPv6 address by DHCPv6 API. */
297     status = nx_dhcpv6_get_IP_address(&dhcp_client, &ipv6_address);
298 
299     /* Check status.  */
300     if (status != NX_SUCCESS)
301     {
302         printf("ERROR!\n");
303         test_control_return(1);
304     }
305 
306     /* Check the address.  */
307     if ((ipv6_address.nxd_ip_version != start_ipv6_address.nxd_ip_version) ||
308         (ipv6_address.nxd_ip_address.v6[0] != start_ipv6_address.nxd_ip_address.v6[0]) ||
309         (ipv6_address.nxd_ip_address.v6[1] != start_ipv6_address.nxd_ip_address.v6[1]) ||
310         (ipv6_address.nxd_ip_address.v6[2] != start_ipv6_address.nxd_ip_address.v6[2]) ||
311         (ipv6_address.nxd_ip_address.v6[3] != start_ipv6_address.nxd_ip_address.v6[3]))
312     {
313         printf("ERROR!\n");
314         test_control_return(1);
315     }
316 
317     /* Get the IPv6 address by NetX Duo API. */
318     status = nxd_ipv6_address_get(&client_ip, 1, &ipv6_address, &prefix_length, &interface_index);
319 
320     /* Check status.  */
321     if (status != NX_SUCCESS)
322     {
323         printf("ERROR!\n");
324         test_control_return(1);
325     }
326 
327     /* Check the IPv6 address.  */
328     if ((prefix_length != 64) || (interface_index != 0) ||
329         (ipv6_address.nxd_ip_version != start_ipv6_address.nxd_ip_version) ||
330         (ipv6_address.nxd_ip_address.v6[0] != start_ipv6_address.nxd_ip_address.v6[0]) ||
331         (ipv6_address.nxd_ip_address.v6[1] != start_ipv6_address.nxd_ip_address.v6[1]) ||
332         (ipv6_address.nxd_ip_address.v6[2] != start_ipv6_address.nxd_ip_address.v6[2]) ||
333         (ipv6_address.nxd_ip_address.v6[3] != start_ipv6_address.nxd_ip_address.v6[3]))
334     {
335         printf("ERROR!\n");
336         test_control_return(1);
337     }
338 
339     /* Get IP address lease time.
340        Note, This API only applies to one IA. */
341     status = nx_dhcpv6_get_lease_time_data(&dhcp_client, &T1, &T2, &preferred_lifetime, &valid_lifetime);
342 
343     /* Check status.  */
344     if (status != NX_SUCCESS)
345     {
346         printf("ERROR!\n");
347         test_control_return(1);
348     }
349 
350     /* Check the value.  */
351     if ((T1 != NX_DHCPV6_DEFAULT_T1_TIME) ||
352         (T2 != NX_DHCPV6_DEFAULT_T2_TIME) ||
353         (preferred_lifetime != NX_DHCPV6_DEFAULT_PREFERRED_TIME) ||
354         (valid_lifetime != NX_DHCPV6_DEFAULT_VALID_TIME))
355     {
356         printf("ERROR!\n");
357         test_control_return(1);
358     }
359 
360     /* Get the DNS Server address. */
361     status = nx_dhcpv6_get_DNS_server_address(&dhcp_client, 0, &dns_address);
362 
363     /* Check status.  */
364     if (status != NX_SUCCESS)
365     {
366         printf("ERROR!\n");
367         test_control_return(1);
368     }
369 
370     /* Check the IPv6 DNS address.  */
371     if ((dns_address.nxd_ip_version != dns_ipv6_address.nxd_ip_version) ||
372         (dns_address.nxd_ip_address.v6[0] != dns_ipv6_address.nxd_ip_address.v6[0]) ||
373         (dns_address.nxd_ip_address.v6[1] != dns_ipv6_address.nxd_ip_address.v6[1]) ||
374         (dns_address.nxd_ip_address.v6[2] != dns_ipv6_address.nxd_ip_address.v6[2]) ||
375         (dns_address.nxd_ip_address.v6[3] != dns_ipv6_address.nxd_ip_address.v6[3]))
376     {
377         printf("ERROR!\n");
378         test_control_return(1);
379     }
380 
381     /* Ping the DHCPv6 Server.  */
382     status = nxd_icmp_ping(&client_ip, &server_address, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 28, &my_packet, NX_IP_PERIODIC_RATE);
383 
384     /* Check for errors.  */
385     if (status)
386     {
387         printf("ERROR!\n");
388         test_control_return(1);
389     }
390 
391     /* Release the address.  */
392     status = nx_dhcpv6_request_release(&dhcp_client);
393 
394     /* Check status.  */
395     if (status)
396     {
397         printf("ERROR!\n");
398         test_control_return(1);
399     }
400 
401     /* Waiting for release the IPv6 address. */
402     tx_thread_sleep(NX_IP_PERIODIC_RATE);
403 
404     /* Get the IPv6 address by DHCPv6 API. */
405     status = nx_dhcpv6_get_IP_address(&dhcp_client, &ipv6_address);
406 
407     /* Check status.  */
408     if (status == NX_SUCCESS)
409     {
410         printf("ERROR!\n");
411         test_control_return(1);
412     }
413 
414     /* Get the IPv6 address by NetX Duo API. */
415     status = nxd_ipv6_address_get(&client_ip, 1, &ipv6_address, &prefix_length, &interface_index);
416 
417     /* Check status.  */
418     if (status == NX_SUCCESS)
419     {
420         printf("ERROR!\n");
421         test_control_return(1);
422     }
423 
424     /* Stop the Client task. */
425     status = nx_dhcpv6_stop(&dhcp_client);
426 
427     /* Check status.  */
428     if (status)
429     {
430         printf("ERROR!\n");
431         test_control_return(1);
432     }
433 
434     /* Delete the DHCPv6 client. */
435     status = nx_dhcpv6_client_delete(&dhcp_client);
436 
437     /* Check status.  */
438     if (status)
439     {
440         printf("ERROR!\n");
441         test_control_return(1);
442     }
443 
444     /* Output successfully.  */
445     printf("SUCCESS!\n");
446     test_control_return(0);
447 }
448 
449 /* Define the test server thread. */
thread_server_entry(ULONG thread_input)450 void    thread_server_entry(ULONG thread_input)
451 {
452 
453 UINT        status;
454 ULONG       duid_time;
455 UINT        addresses_added;
456 
457     /* Set the IPv6 address of DHCPv6 Server.  */
458     server_address.nxd_ip_version = NX_IP_VERSION_V6 ;
459     server_address.nxd_ip_address.v6[0] = 0x20010db8;
460     server_address.nxd_ip_address.v6[1] = 0xf101;
461     server_address.nxd_ip_address.v6[2] = 0x00000000;
462     server_address.nxd_ip_address.v6[3] = 0x00000101;
463 
464     /* Set the link local and global addresses. */
465     status = nxd_ipv6_address_set(&server_ip, 0, NX_NULL, 10, NULL);
466     status += nxd_ipv6_address_set(&server_ip, 0, &server_address, 64, NULL);
467 
468     /* Check for errors. */
469     if(status)
470     {
471         printf("ERROR!\n");
472         test_control_return(1);
473     }
474 
475     /* Validate the link local and global addresses. */
476     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
477 
478     /* Create the DHCPv6 Server. */
479     status =  nx_dhcpv6_server_create(&dhcp_server, &server_ip, "DHCPv6 Server", &pool_0, pointer, NX_DHCPV6_SERVER_THREAD_STACK_SIZE, NX_NULL, NX_NULL);
480     pointer += NX_DHCPV6_SERVER_THREAD_STACK_SIZE;
481 
482     /* Check for errors.  */
483     if(status)
484     {
485         printf("ERROR!\n");
486         test_control_return(1);
487     }
488 
489     /* Set up the DNS IPv6 server address. */
490     dns_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
491     dns_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
492     dns_ipv6_address.nxd_ip_address.v6[1] = 0x0000f101;
493     dns_ipv6_address.nxd_ip_address.v6[2] = 0x00000000;
494     dns_ipv6_address.nxd_ip_address.v6[3] = 0x00000107;
495 
496     status = nx_dhcpv6_create_dns_address(&dhcp_server, &dns_ipv6_address);
497 
498     /* Check for errors. */
499     if(status)
500     {
501         printf("ERROR!\n");
502         test_control_return(1);
503     }
504 
505      /* Note: For DUID types that do not require time, the 'duid_time' input can be left at zero.
506         The DUID_TYPE and HW_TYPE are configurable options that are user defined in nx_dhcpv6_server.h.  */
507 
508     /* Set the DUID time as the start of the millenium. */
509     duid_time = SECONDS_SINCE_JAN_1_2000_MOD_32;
510     status = nx_dhcpv6_set_server_duid(&dhcp_server,
511                                     NX_DHCPV6_SERVER_DUID_TYPE, NX_DHCPV6_SERVER_HW_TYPE,
512                                     dhcp_server.nx_dhcpv6_ip_ptr -> nx_ip_arp_physical_address_msw,
513                                     dhcp_server.nx_dhcpv6_ip_ptr -> nx_ip_arp_physical_address_lsw,
514                                     duid_time);
515 
516     /* Check for errors. */
517     if(status)
518     {
519         printf("ERROR!\n");
520         test_control_return(1);
521     }
522 
523     /* Set the IPv6 start address.  */
524     start_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
525     start_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
526     start_ipv6_address.nxd_ip_address.v6[1] = 0x00000f101;
527     start_ipv6_address.nxd_ip_address.v6[2] = 0x0;
528     start_ipv6_address.nxd_ip_address.v6[3] = 0x00000110;
529 
530     /* Set the IPv6 end address.  */
531     end_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
532     end_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
533     end_ipv6_address.nxd_ip_address.v6[1] = 0x0000f101;
534     end_ipv6_address.nxd_ip_address.v6[2] = 0x00000000;
535     end_ipv6_address.nxd_ip_address.v6[3] = 0x00000120;
536 
537     /* Set the IPv6 address range.  */
538     status = nx_dhcpv6_create_ip_address_range(&dhcp_server, &start_ipv6_address, &end_ipv6_address, &addresses_added);
539 
540     /* Check for errors. */
541     if ((status) || (addresses_added != 16))
542     {
543         printf("ERROR!\n");
544         test_control_return(1);
545     }
546 
547     /* Start the NetX DHCPv6 server!  */
548     status =  nx_dhcpv6_server_start(&dhcp_server);
549 
550     /* Check for errors. */
551     if(status)
552     {
553         printf("ERROR!\n");
554         test_control_return(1);
555     }
556 }
557 #else
558 #ifdef CTEST
test_application_define(void * first_unused_memory)559 VOID test_application_define(void *first_unused_memory)
560 #else
561 void netx_dhcpv6_basic_test_application_define(void * first_unused_memory)
562 #endif
563 {
564     printf("NetX Test:   DHCPv6 Basic Test.........................................N/A\n");
565     test_control_return(3);
566 }
567 #endif /* FEATURE_NX_IPV6 */
568