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 #include   "nxd_dhcpv6_client.h"
8 #include   "nxd_dhcpv6_server.h"
9 
10 #define     DEMO_DATA               "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
11 
12 #ifdef FEATURE_NX_IPV6
13 
14 #define     DEMO_STACK_SIZE                     2048
15 #define     NX_DHCPV6_THREAD_STACK_SIZE         2048
16 
17 /* Define the ThreadX and NetX object control blocks...  */
18 
19 NX_PACKET_POOL          pool_0;
20 TX_THREAD               thread_client;
21 NX_IP                   client_ip;
22 TX_THREAD               thread_server;
23 NX_IP                   server_ip;
24 
25 /* Define the Client and Server instances. */
26 
27 NX_DHCPV6               dhcp_client;
28 NX_DHCPV6_SERVER        dhcp_server;
29 
30 /* Define the variables.  */
31 
32 CHAR                    *pointer;
33 NXD_ADDRESS             server_address;
34 NXD_ADDRESS             dns_ipv6_address;
35 NXD_ADDRESS             start_ipv6_address;
36 NXD_ADDRESS             end_ipv6_address;
37 
38 
39 /* Define thread prototypes.  */
40 
41 void    thread_client_entry(ULONG thread_input);
42 void    thread_server_entry(ULONG thread_input);
43 
44 /***** Substitute your ethernet driver entry function here *********/
45 VOID    _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);
46 
47 
48 /* Define some DHCPv6 parameters. */
49 
50 #define DHCPV6_IANA_ID                  0xABCDEFAB
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 main entry point.  */
58 
main()59 int main()
60 {
61 
62     /* Enter the ThreadX kernel.  */
63     tx_kernel_enter();
64 }
65 
66 
67 /* Define what the initial system looks like.  */
68 
tx_application_define(void * first_unused_memory)69 void    tx_application_define(void *first_unused_memory)
70 {
71 
72 UINT    status;
73 
74     /* Setup the working pointer.  */
75     pointer =  (CHAR *) first_unused_memory;
76 
77     /* Initialize the NetX system.  */
78     nx_system_initialize();
79 
80     /* Create the Client thread.  */
81     status = tx_thread_create(&thread_client, "Client thread", thread_client_entry, 0,
82                               pointer, DEMO_STACK_SIZE,
83                               4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
84     pointer = pointer + DEMO_STACK_SIZE;
85 
86     /* Check for thread create errors.  */
87     if (status)
88         return;
89 
90     /* Create the Server thread.  */
91     status = tx_thread_create(&thread_server, "Server thread", thread_server_entry, 0,
92                               pointer, DEMO_STACK_SIZE,
93                               3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
94     pointer = pointer + DEMO_STACK_SIZE;
95 
96     /* Check for thread create errors.  */
97     if (status)
98         return;
99 
100     /* Create a packet pool.  */
101     status =  nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 1024, pointer, NX_DHCPV6_PACKET_POOL_SIZE);
102     pointer = pointer + NX_DHCPV6_PACKET_POOL_SIZE;
103 
104     /* Check for pool creation error.  */
105     if (status)
106         return;
107 
108     /* Create a Client IP instance.  */
109     status = nx_ip_create(&client_ip, "Client IP", IP_ADDRESS(0, 0, 0, 0),
110                           0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
111                           pointer, 2048, 1);
112     pointer = pointer + 2048;
113 
114     /* Check for IP create errors.  */
115     if (status)
116         return;
117 
118     /* Create a Server IP instance.  */
119     status = nx_ip_create(&server_ip, "Server IP", IP_ADDRESS(1, 2, 3, 4),
120                           0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
121                           pointer, 2048, 1);
122     pointer = pointer + 2048;
123 
124     /* Check for IP create errors.  */
125     if (status)
126         return;
127 
128     /* Enable UDP traffic for sending DHCPv6 messages.  */
129     status =  nx_udp_enable(&client_ip);
130     status +=  nx_udp_enable(&server_ip);
131 
132     /* Check for UDP enable errors.  */
133     if (status)
134         return;
135 
136     /* Enable the IPv6 services. */
137     status = nxd_ipv6_enable(&client_ip);
138     status += nxd_ipv6_enable(&server_ip);
139 
140     /* Check for IPv6 enable errors.  */
141     if (status)
142         return;
143 
144     /* Enable the ICMPv6 services. */
145     status = nxd_icmp_enable(&client_ip);
146     status += nxd_icmp_enable(&server_ip);
147 
148     /* Check for ICMPv6 enable errors.  */
149     if (status)
150         return;
151 }
152 
153 /* Define the Client host application thread. */
154 
thread_client_entry(ULONG thread_input)155 void    thread_client_entry(ULONG thread_input)
156 {
157 
158 UINT        status;
159 
160 #ifdef  GET_ONE_SPECIFIC_ADDRESS
161 NXD_ADDRESS ia_ipv6_address;
162 #endif
163 
164 NXD_ADDRESS ipv6_address;
165 NXD_ADDRESS dns_address;
166 ULONG       T1, T2, preferred_lifetime, valid_lifetime;
167 UINT        address_count;
168 UINT        address_index;
169 UINT        dns_index;
170 NX_PACKET   *my_packet;
171 
172     NX_PARAMETER_NOT_USED(thread_input);
173 
174     /* Modified the mtu size to avoid fragmenting the DHCP packet since the default mtu size is 128 in _nx_ram_network_driver.  */
175     status = nx_ip_interface_mtu_set(&server_ip, 0, 1500);
176 
177     /* Check for MTU set errors.  */
178     if (status)
179         return;
180 
181     /* Establish the link local address for the host. The RAM driver creates
182        a virtual MAC address of 0x1122334456. */
183     status = nxd_ipv6_address_set(&client_ip, 0, NX_NULL, 10, NULL);
184 
185     /* Let NetX Duo and the network driver get initialized. Also give the server time to get set up. */
186     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
187 
188     /* Create the DHCPv6 Client. */
189     status =  nx_dhcpv6_client_create(&dhcp_client, &client_ip, "DHCPv6 Client", &pool_0, pointer, NX_DHCPV6_THREAD_STACK_SIZE,
190                                       NX_NULL, NX_NULL);
191     pointer = pointer + NX_DHCPV6_THREAD_STACK_SIZE;
192 
193     /* Check for errors.  */
194     if (status)
195         return;
196 
197     /* Create a Link Layer Plus Time DUID for the DHCPv6 Client. Set time ID field
198        to NULL; the DHCPv6 Client API will supply one. */
199     status = nx_dhcpv6_create_client_duid(&dhcp_client, NX_DHCPV6_DUID_TYPE_LINK_TIME,
200                                           NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET, 0);
201 
202     /* Check for errors.  */
203     if (status)
204         return;
205 
206     /* Create the DHCPv6 client's Identity Association (IA-NA) now.
207 
208        Note that if this host had already been assigned in IPv6 lease, it
209        would have to use the assigned T1 and T2 values in loading the DHCPv6
210        client with an IANA block.
211     */
212     status = nx_dhcpv6_create_client_iana(&dhcp_client, DHCPV6_IANA_ID, DHCPV6_T1,  DHCPV6_T2);
213 
214     /* Check for errors.  */
215     if (status)
216         return;
217 
218     /* Starting up the NetX DHCPv6 Client. */
219     status =  nx_dhcpv6_start(&dhcp_client);
220 
221     /* Check for errors.  */
222     if (status)
223         return;
224 
225     /* Let DHCPv6 Server start. */
226     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
227 
228 #ifdef  GET_ONE_SPECIFIC_ADDRESS
229 
230     /* Create an IA address option.
231        The client includs IA options for any IAs to which it wants the server to assign addresses.
232     */
233     ia_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
234     ia_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
235     ia_ipv6_address.nxd_ip_address.v6[1] = 0x00000f101;
236     ia_ipv6_address.nxd_ip_address.v6[2] = 0x0;
237     ia_ipv6_address.nxd_ip_address.v6[3] = 0x00000115;
238     status = nx_dhcpv6_create_client_ia(&dhcp_client, &ia_ipv6_address, NX_DHCPV6_REFERRED_LIFETIME,
239                                         NX_DHCPV6_VALID_LIFETIME);
240 
241     /* Check for errors.  */
242     if (status != NX_SUCCESS)
243         return;
244 #endif
245 
246     /* If the host also want to get the option message, set the list of desired options to enabled. */
247     nx_dhcpv6_request_option_timezone(&dhcp_client, NX_TRUE);
248     nx_dhcpv6_request_option_DNS_server(&dhcp_client, NX_TRUE);
249     nx_dhcpv6_request_option_time_server(&dhcp_client, NX_TRUE);
250     nx_dhcpv6_request_option_domain_name(&dhcp_client, NX_TRUE);
251 
252     /* Now, the host send the solicit message to get the IPv6 address and other options from the DHCPv6 server. */
253     status = nx_dhcpv6_request_solicit(&dhcp_client);
254 
255     /* Check status.  */
256     if (status)
257         return;
258 
259     /* Waiting for get the IPv6 address and do the duplicate address detection. */
260     /*
261         Note, if the host detect another host withe the same address, the DHCPv6 Client can automatically
262         declient the address. At time T1 for an IPv6 address, the DHCPv6 Client can automatically renew the address.
263         At time T2 for an IPv6 address, the DHCPv6 Client can automatically rebind the address.
264         At time valid lifetime for an IPv6 address, the DHCPv6 Client can automatically delete the IPv6 address.
265     */
266     tx_thread_sleep(6 * NX_IP_PERIODIC_RATE);
267 
268     /* Get the T1 and T2 value of IANA option.  */
269     status = nx_dhcpv6_get_iana_lease_time(&dhcp_client, &T1, &T2);
270 
271     /* Check status.  */
272     if (status)
273         return;
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 status.  */
279     if (status)
280         return;
281 
282     /* Get the IPv6 address, preferred lifetime and valid lifetime according to the address index. */
283     address_index = 0;
284     status = nx_dhcpv6_get_valid_ip_address_lease_time(&dhcp_client, address_index, &ipv6_address, &preferred_lifetime, &valid_lifetime);
285 
286     /* Check status.  */
287     if (status)
288         return;
289 
290     /* Get the IPv6 address.
291        Note, This API only applies to one IA. */
292     status = nx_dhcpv6_get_IP_address(&dhcp_client, &ipv6_address);
293 
294     /* Check status.  */
295     if (status)
296         return;
297 
298     /* Get IP address lease time.
299        Note, This API only applies to one IA. */
300     status = nx_dhcpv6_get_lease_time_data(&dhcp_client, &T1, &T2, &preferred_lifetime, &valid_lifetime);
301 
302     /* Check status.  */
303     if (status)
304         return;
305 
306     /* Get the DNS Server address lease time. */
307     dns_index = 0;
308     status = nx_dhcpv6_get_DNS_server_address(&dhcp_client, dns_index, &dns_address);
309 
310     /* Check status.  */
311     if (status)
312         return;
313 
314     /**************************************************/
315     /* Ping the DHCPv6 Server, Test the IPv6 address. */
316     /**************************************************/
317 
318     /* Ping the IPv6 address of DHCPv6 Server.  */
319     status = nxd_icmp_ping(&client_ip, &server_address, DEMO_DATA, sizeof(DEMO_DATA), &my_packet, NX_IP_PERIODIC_RATE);
320 
321     /* Check status.  */
322     if (status)
323         return;
324 
325     /* If we want to release the address, we can send release message to
326        the server we are releasing the assigned address.  */
327     status = nx_dhcpv6_request_release(&dhcp_client);
328 
329     /* Check status.  */
330     if (status)
331         return;
332 
333     /* Stop the Client task. */
334     status = nx_dhcpv6_stop(&dhcp_client);
335 
336     /* Check status.  */
337     if (status)
338         return;
339 
340     /* Now delete the DHCPv6 client. */
341     status = nx_dhcpv6_client_delete(&dhcp_client);
342 
343     /* Check status.  */
344     if (status)
345         return;
346 }
347 
348 /* Define the test server thread. */
349 
thread_server_entry(ULONG thread_input)350 void    thread_server_entry(ULONG thread_input)
351 {
352 
353 UINT        status;
354 ULONG       duid_time;
355 UINT        addresses_added;
356 
357     NX_PARAMETER_NOT_USED(thread_input);
358 
359     /* Modified the mtu size to avoid fragmenting the DHCP packet since the default mtu size is 128 in _nx_ram_network_driver.  */
360     status = nx_ip_interface_mtu_set(&client_ip, 0, 1500);
361 
362     /* Check for MTU set errors.  */
363     if (status)
364         return;
365 
366     /* Set the IPv6 address of DHCPv6 Server.  */
367     server_address.nxd_ip_version = NX_IP_VERSION_V6 ;
368     server_address.nxd_ip_address.v6[0] = 0x20010db8;
369     server_address.nxd_ip_address.v6[1] = 0xf101;
370     server_address.nxd_ip_address.v6[2] = 0x00000000;
371     server_address.nxd_ip_address.v6[3] = 0x00000101;
372 
373     /* Set the link local and global addresses. */
374     status = nxd_ipv6_address_set(&server_ip, 0, NX_NULL, 10, NULL);
375     status += nxd_ipv6_address_set(&server_ip, 0, &server_address, 64, NULL);
376 
377     /* Check for errors. */
378     if (status)
379         return;
380 
381     /* Create the DHCPv6 Server. */
382     status =  nx_dhcpv6_server_create(&dhcp_server, &server_ip, "DHCPv6 Server", &pool_0, pointer, NX_DHCPV6_SERVER_THREAD_STACK_SIZE, NX_NULL, NX_NULL);
383     pointer = pointer + NX_DHCPV6_SERVER_THREAD_STACK_SIZE;
384 
385     /* Check for errors.  */
386     if (status)
387         return;
388 
389     /* Note this example assumes a single global IP address on the primary interface.  If otherwise
390        the host should call the service to set the network interface and global IP address index.
391 
392         UINT _nx_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT interface_index, UINT address_index)
393     */
394 
395     /* Validate the link local and global addresses. */
396     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
397 
398     /* Set up the DNS IPv6 server address. */
399     dns_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
400     dns_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
401     dns_ipv6_address.nxd_ip_address.v6[1] = 0x0000f101;
402     dns_ipv6_address.nxd_ip_address.v6[2] = 0x00000000;
403     dns_ipv6_address.nxd_ip_address.v6[3] = 0x00000107;
404 
405     status = nx_dhcpv6_create_dns_address(&dhcp_server, &dns_ipv6_address);
406 
407     /* Check for errors. */
408     if (status)
409         return;
410 
411      /* Note: For DUID types that do not require time, the 'duid_time' input can be left at zero.
412         The DUID_TYPE and HW_TYPE are configurable options that are user defined in nx_dhcpv6_server.h.  */
413 
414     /* Set the DUID time as the start of the millenium. */
415     duid_time = SECONDS_SINCE_JAN_1_2000_MOD_32;
416     status = nx_dhcpv6_set_server_duid(&dhcp_server,
417                                     NX_DHCPV6_SERVER_DUID_TYPE, NX_DHCPV6_SERVER_HW_TYPE,
418                                     dhcp_server.nx_dhcpv6_ip_ptr -> nx_ip_arp_physical_address_msw,
419                                     dhcp_server.nx_dhcpv6_ip_ptr -> nx_ip_arp_physical_address_lsw,
420                                     duid_time);
421 
422     /* Check for errors. */
423     if (status)
424         return;
425 
426     /* Set the IPv6 start address.  */
427     start_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
428     start_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
429     start_ipv6_address.nxd_ip_address.v6[1] = 0x00000f101;
430     start_ipv6_address.nxd_ip_address.v6[2] = 0x0;
431     start_ipv6_address.nxd_ip_address.v6[3] = 0x00000110;
432 
433     /* Set the IPv6 end address.  */
434     end_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
435     end_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
436     end_ipv6_address.nxd_ip_address.v6[1] = 0x0000f101;
437     end_ipv6_address.nxd_ip_address.v6[2] = 0x00000000;
438     end_ipv6_address.nxd_ip_address.v6[3] = 0x00000120;
439 
440     /* Set the IPv6 address range.  */
441     status = nx_dhcpv6_create_ip_address_range(&dhcp_server, &start_ipv6_address, &end_ipv6_address, &addresses_added);
442 
443     /* Check for errors. */
444     if (status)
445         return;
446 
447     /* Start the NetX DHCPv6 server!  */
448     status =  nx_dhcpv6_server_start(&dhcp_server);
449 
450     /* Check for errors. */
451     if (status)
452         return;
453 }
454 #endif /* FEATURE_NX_IPV6 */
455