This chapter contains a description of various issues related to installation, setup, and usage of the NetX Duo DHCPv6 Server.
NetX Duo can be obtained from our public source code repository at https://github.com/eclipse-threadx/netxduo/.
nxd_dhcpv6_server.h NetX DuoDHCPv6Server header file
nxd_dhcpv6_server.c NetX DuoDHCPv6Server source file
demo_netxduo_dhcpv6.c NetX Duo DHCPv6 Server demo file
nxd_dhcpv6_server.pdf NetX Duo DHCPv6Server User Guide
In order to use the NetX Duo DHCPv6Server API, the entire distribution mentioned previously should be copied to the same directory where NetX Duo is installed. For example, if NetX Duo is installed in the directory β\threadx\arm7\greenβ then the nxd_dhcpv6_server.h and nx_dhpcv6_server.c files should be copied into this directory.
Using the NetX Duo DHCPv6Server API is easy. Basically, the application code must include nx_dhcpv6-server.h after it includes tx_api.h and nx_api.h, in order to use ThreadX and NetX Duo, respectively. The application must also include nxd_dhcpv6_server.c in the build process. This file must be compiled in the same manner as other application files and its object form must be linked along with the files of the application. This is all that is required to use NetX Duo DHCPv6 Server.
Note that since DHCPv6is based on the IPv6 protocol, IPv6 must be enabled on the IP instance using nxd_ipv6_enable. NetX Duo UDP and ICMPv6 services are also utilized. UDP is enabled by calling nx_udp_enable and ICMPv6is enabled by calling nxd_icmp_enable prior to starting the NetX Duo DHCPv6 Server thread task.
An example of how easy it is to use the NetX Duo DHCPv6 Server is described in the small example below using a DHCPv6 Client and Server running over a virtual βRAMβ driver. This demo assumes a single homed host using the NetX Duo environment.
tx_application_define creates packet pool for sending DHCPv6 message, a thread and an IP instance for both the Client and Server, and enables UDP (DHCP runs over UDP), IPv6, ICMP and ICMPv6 for both Client and Server IP tasks in lines 116-157.
The DHCPv6 Server is created in line 456. It does not define the optional address decline or option request handlers. In the Server thread entry function, the Server IP is set up with a link local address services in lines 435-453.
Before starting the DHCPv6 Server, the host application creates a Server DUID in line 498 and sets the local network DNS server on line 483. It then creates a table of assignable IP addresses in lines 521. See the Advanced Example System in Appendix D for how to store and retrieve Server tables from memory.
Then the DHCPv6 Server is ready to start on line 530.
For details on creating and running the NetX Duo DHCPv6 Client see the nxd_dhcpv6_client.pdf file distributed on with the DHCPv6 Server.
1 /* This is a small demo of the NetX Duo DHCPv6 Client and Server for the
2 high-performance 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 #ifdef FEATURE_NX_IPV6
11
12 #define DEMO_STACK_SIZE 2048
13 #define NX_DHCPV6_THREAD_STACK_SIZE 2048
14
15 /* Define the ThreadX and NetX object control blocks... */
16
17 NX_PACKET_POOL pool_0;
18 TX_THREAD thread_client;
19 NX_IP client_ip;
20 TX_THREAD thread_server;
21 NX_IP server_ip;
22
23 /* Define the Client and Server instances. */
24
25 NX_DHCPV6 dhcp_client;
26 NX_DHCPV6_SERVER dhcp_server;
27
28 /* Define the error counter used in the demo application... */
29 ULONG error_counter;
30 CHAR *pointer;
31
32 NXD_ADDRESS server_address;
33 NXD_ADDRESS dns_ipv6_address;
34 NXD_ADDRESS start_ipv6_address;
35 NXD_ADDRESS end_ipv6_address;
36
37
38 /* Define thread prototypes. */
39
40 void thread_client_entry(ULONG thread_input);
41 void thread_server_entry(ULONG thread_input);
42
43 /***** Substitute your ethernet driver entry function here *********/
44 VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);
45
46
47 /* Define some DHCPv6 parameters. */
48
49 #define DHCPV6_IANA_ID 0xC0DEDBAD
50 #define DHCPV6_T1 NX_DHCPV6_INFINITE_LEASE
51 #define DHCPV6_T2 NX_DHCPV6_INFINITE_LEASE
52 #define NX_DHCPV6_REFERRED_LIFETIME NX_DHCPV6_INFINITE_LEASE
53 #define NX_DHCPV6_VALID_LIFETIME NX_DHCPV6_INFINITE_LEASE
54
55
56 /* Define main entry point. */
57
58 int main()
59 {
60
61 /* Enter the ThreadX kernel. */
62 tx_kernel_enter();
63 }
64
65
66 /* Define what the initial system looks like. */
67
68 void tx_application_define(void *first_unused_memory)
69 {
70
71 UINT status;
72
73 /* Setup the working pointer. */
74 pointer = (CHAR *) first_unused_memory;
75
76 /* Initialize the NetX system. */
77 nx_system_initialize();
78
79 /* Create a packet pool. */
80 status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 1024, pointer,
NX_DHCPV6_PACKET_POOL_SIZE);
81 pointer = pointer + NX_DHCPV6_PACKET_POOL_SIZE;
82
83 /* Check for pool creation error. */
84 if (status)
85 error_counter++;
86
87 /* Create a Client IP instance. */
88 status = nx_ip_create(&client_ip, "Client IP", IP_ADDRESS(0, 0, 0, 0),
89 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
90 pointer, 2048, 1);
91
92 pointer = pointer + 2048;
93
94 /* Check for IP create errors. */
95 if (status)
96 {
97 error_counter++;
98 return;
99 }
100
101 /* Create a Server IP instance. */
102 status = nx_ip_create(&server_ip, "Server IP", IP_ADDRESS(1, 2, 3, 4),
103 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
104 pointer, 2048, 1);
105
106 pointer = pointer + 2048;
107
108 /* Check for IP create errors. */
109 if (status)
110 {
111 error_counter++;
112 return;
113 }
114
115 /* Enable UDP traffic for sending DHCPv6 messages. */
116 status = nx_udp_enable(&client_ip);
117 status += nx_udp_enable(&server_ip);
118
119 /* Check for UDP enable errors. */
120 if (status)
121 {
122 error_counter++;
123 return;
124 }
125
126 /* Enable ICMP. */
127 status = nx_icmp_enable(&client_ip);
128 status += nx_icmp_enable(&server_ip);
129
130 /* Check for ICMP enable errors. */
131 if (status)
132 {
133 error_counter++;
134 return;
135 }
136
137 /* Enable the IPv6 services. */
138 status = nxd_ipv6_enable(&client_ip);
139 status += nxd_ipv6_enable(&server_ip);
140
141 /* Check for IPv6 enable errors. */
142 if (status)
143 {
144 error_counter++;
145 return;
146 }
147
148 /* Enable the ICMPv6 services. */
149 status = nxd_icmp_enable(&client_ip);
150 status += nxd_icmp_enable(&server_ip);
151
152 /* Check for ICMP enable errors. */
153 if (status)
154 {
155 error_counter++;
156 return;
157 }
158
159 /* Create the Client thread. */
160 status = tx_thread_create(&thread_client, "Client thread", thread_client_entry, 0,
161 pointer, DEMO_STACK_SIZE,
162 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
163 /* Check for IP create errors. */
164 if (status)
165 {
166 error_counter++;
167 return;
168 }
169
170 pointer = pointer + DEMO_STACK_SIZE;
171
172 /* Create the Server thread. */
173 status = tx_thread_create(&thread_server, "Server thread", thread_server_entry, 0,
174 pointer, DEMO_STACK_SIZE,
175 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
176 /* Check for IP create errors. */
177 if (status)
178 {
179 error_counter++;
180 return;
181 }
182
183 pointer = pointer + DEMO_STACK_SIZE;
184
185 /* Yield control to DHCPv6 threads and ThreadX. */
186 return;
187 }
188
189 /* Define the Client host application thread. */
190
191 void thread_client_entry(ULONG thread_input)
192 {
193
194 UINT status;
195
196 #ifdef GET_ONE_SPECIFIC_ADDRESS
197 NXD_ADDRESS ia_ipv6_address;
198 #endif
199
200 NXD_ADDRESS ipv6_address;
201 NXD_ADDRESS dns_address;
202 ULONG T1, T2, preferred_lifetime, valid_lifetime;
203 UINT address_count;
204 UINT address_index;
205 UINT dns_index;
206 NX_PACKET *my_packet;
207
208
209 /* Establish the link local address for the host. The RAM driver creates
210 a virtual MAC address of 0x1122334456. */
211 status = nxd_ipv6_address_set(&client_ip, 0, NX_NULL, 10, NULL);
212
213 /* Let NetX Duo and the network driver get initialized. Also give the server time to get set up. */
214 tx_thread_sleep(300);
215
216
217 /* Create the DHCPv6 Client. */
218 status = nx_dhcpv6_client_create(&dhcp_client, &client_ip, "DHCPv6 Client",
&pool_0, pointer, NX_DHCPV6_THREAD_STACK_SIZE,
219 NX_NULL, NX_NULL);
220
221 /* Check for errors. */
222 if (status)
223 {
224 error_counter++;
225 return;
226 }
227
228 /* Update the stack pointer because we need it again. */
229 pointer = pointer + NX_DHCPV6_THREAD_STACK_SIZE;
230
231 /* Create a Link Layer Plus Time DUID for the DHCPv6 Client. Set time ID field
232 to NULL; the DHCPv6 Client API will supply one. */
233 status = nx_dhcpv6_create_client_duid(&dhcp_client, NX_DHCPV6_DUID_TYPE_LINK_TIME,
234 NX_DHCPV6_HW_TYPE_IEEE_802, 0);
235
236 if (status != NX_SUCCESS)
237 {
238 error_counter++;
239 return;
240 }
241
242 /* Create the DHCPv6 client's Identity Association (IA-NA) now.
243
244 Note that if this host had already been assigned in IPv6 lease, it
245 would have to use the assigned T1 and T2 values in loading the DHCPv6
246 client with an IANA block.
247 */
248 status = nx_dhcpv6_create_client_iana(&dhcp_client, DHCPV6_IANA_ID, DHCPV6_T1, DHCPV6_T2);
249
250 if (status != NX_SUCCESS)
251 {
252 error_counter++;
253 return;
254 }
255
256 /* Starting up the NetX DHCPv6 Client. */
257 status = nx_dhcpv6_start(&dhcp_client);
258
259 /* Check for errors. */
260 if (status != NX_SUCCESS)
261 {
262
263 return;
264 }
265
266 /* Let DHCPv6 Server start. */
267 tx_thread_sleep(500);
268
269 #ifdef GET_ONE_SPECIFIC_ADDRESS
270
271 /* Create an IA address option.
272
273 The client includes IA options for any IAs to which it wants the server
to assign addresses.
274 */
275
276 memset(&ia_ipv6_address,0x0, sizeof(NXD_ADDRESS));
277 ia_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
278 ia_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
279 ia_ipv6_address.nxd_ip_address.v6[1] = 0x00000f101;
280 ia_ipv6_address.nxd_ip_address.v6[2] = 0x0;
281 ia_ipv6_address.nxd_ip_address.v6[3] = 0x00000115;
282
283 status = nx_dhcpv6_create_client_ia(&dhcp_client, &ia_ipv6_address
NX_DHCPV6_REFERRED_LIFETIME,
284 NX_DHCPV6_VALID_LIFETIME);
285
286 if (status != NX_SUCCESS)
287 {
288 error_counter++;
289 return;
290 }
291
292 #endif
293
294 /* If the host also want to get the option message, set the list of
desired options to enabled. */
295 nx_dhcpv6_request_option_timezone(&dhcp_client, NX_TRUE);
296 nx_dhcpv6_request_option_DNS_server(&dhcp_client, NX_TRUE);
297 nx_dhcpv6_request_option_time_server(&dhcp_client, NX_TRUE);
298 nx_dhcpv6_request_option_domain_name(&dhcp_client, NX_TRUE);
299
300 /* Now, the host send the solicit message to get the IPv6 address and
other options from the DHCPv6 server. */
301 status = nx_dhcpv6_request_solicit(&dhcp_client);
302
303 /* Check status. */
304 if (status != NX_SUCCESS)
305 {
306
307 error_counter++;
308 return;
309 }
310
311 /* Waiting for get the IPv6 address and do the duplicate address detection. */
312 /*
313 Note, if the host detect another host withe the same address, the DHCPv6
Client can automatically
314 declient the address. At time T1 for an IPv6 address, the DHCPv6 Client can automatically renew the address.
315 At time T2 for an IPv6 address, the DHCPv6 Client can automatically rebind the address.
316 At time valid lifetime for an IPv6 address, the DHCPv6 Client can automatically delete the IPv6 address.
317 */
318 tx_thread_sleep(500);
319
320
321 /* Get the T1 and T2 value of IANA option. */
322 status = nx_dhcpv6_get_iana_lease_time(&dhcp_client, &T1, &T2);
323
324 /* Check status. */
325 if (status != NX_SUCCESS)
326 {
327 error_counter++;
328 }
329
330 /* Get the valid IPv6 address count which the DHCPv6 server assigned . */
331 status = nx_dhcpv6_get_valid_ip_address_count(&dhcp_client, &address_count);
332
333 /* Check status. */
334 if (status != NX_SUCCESS)
335 {
336 error_counter++;
337 }
338
339 /* Get the IPv6 address, preferred lifetime and valid lifetime according to the address index. */
340 address_index = 0;
341 status = nx_dhcpv6_get_valid_ip_address_lease_time(&dhcp_client, address_index,
&ipv6_address, &preferred_lifetime, &valid_lifetime);
342
343 /* Check status. */
344 if (status != NX_SUCCESS)
345 {
346 error_counter++;
347 }
348
349 /* Get the IPv6 address.
350 Note, This API only applies to one IA. */
351 status = nx_dhcpv6_get_IP_address(&dhcp_client, &ipv6_address);
352
353 /* Check status. */
354 if (status != NX_SUCCESS)
355 {
356 error_counter++;
357 }
358
359 /* Get IP address lease time.
360 Note, This API only applies to one IA. */
361 status = nx_dhcpv6_get_lease_time_data(&dhcp_client, &T1, &T2, &preferred_lifetime,
&valid_lifetime);
362
363 /* Check status. */
364 if (status != NX_SUCCESS)
365 {
366 error_counter++;
367 }
368
369 /* Get the DNS Server address lease time. */
370 dns_index = 0;
371 status = nx_dhcpv6_get_DNS_server_address(&dhcp_client, dns_index, &dns_address);
372
373 /* Check status. */
374 if (status != NX_SUCCESS)
375 {
376 error_counter++;
377 }
378
379 /**************************************************/
380 /* Ping the DHCPv6 Server, Test the IPv6 address. */
381 /**************************************************/
382
383 /* Ping an unknown IP address. This will timeout after 100 ticks. */
384 status = nxd_icmp_ping(&client_ip, &server_address, "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
28, &my_packet, 100);
385
386 /* Determine if the timeout error occurred. */
387 if ((status != NX_SUCCESS) || (my_packet == NX_NULL))
388 {
389 error_counter++;
390 }
391
392 /* If we want to release the address, we can send release message to
393 the server we are releasing the assigned address. */
394 status = nx_dhcpv6_request_release(&dhcp_client);
395
396 /* Check status. */
397 if (status != NX_SUCCESS)
398 {
399
400 error_counter++;
401 return;
402 }
403
404 /* Stopping the Client task. */
405 status = nx_dhcpv6_stop(&dhcp_client);
406
407 /* Check status. */
408 if (status != NX_SUCCESS)
409 {
410
411 error_counter++;
412 return;
413 }
414
415 /* Now delete the DHCPv6 client and release ThreadX and NetX resources back to
416 the system. */
417 nx_dhcpv6_client_delete(&dhcp_client);
418
419 return;
420
421 }
422
423 /* Define the test server thread. */
424 void thread_server_entry(ULONG thread_input)
425 {
426
427 UINT status;
428 ULONG duid_time;
429 UINT addresses_added;
430
431
432 /* Wait till the IP task thread has had a chance to set the device MAC address. */
433 tx_thread_sleep(100);
434
435 memset(&server_address,0x0, sizeof(NXD_ADDRESS));
436
437 server_address.nxd_ip_version = NX_IP_VERSION_V6 ;
438 server_address.nxd_ip_address.v6[0] = 0x20010db8;
439 server_address.nxd_ip_address.v6[1] = 0xf101;
440 server_address.nxd_ip_address.v6[2] = 0x00000000;
441 server_address.nxd_ip_address.v6[3] = 0x00000101;
442
443 /* Set the link local and global addresses. */
444 status = nxd_ipv6_address_set(&server_ip, 0, NX_NULL, 10, NULL);
445 status += nxd_ipv6_address_set(&server_ip, 0, &server_address, 64, NULL);
446
447 /* Check for errors. */
448 if (status != NX_SUCCESS)
449 {
450
451 error_counter++;
452 return;
453 }
454
455 /* Create the DHCPv6 Server. */
456 status = nx_dhcpv6_server_create(&dhcp_server, &server_ip, "DHCPv6 Server", &pool_0, pointer, NX_DHCPV6_SERVER_THREAD_STACK_SIZE, NX_NULL, NX_NULL);
457
458 /* Check for errors. */
459 if (status != NX_SUCCESS)
460 {
461 error_counter++;
462 }
463
464 /* Update the stack pointer in case we need it again. */
465 pointer = pointer + NX_DHCPV6_SERVER_THREAD_STACK_SIZE;
466
467 /* Note this example assumes a single global IP address on the primary interface. If otherwise
468 the host should call the service to set the network interface and global IP address index.
469
470 UINT _nx_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT interface_index, UINT address_index)
471 */
472
473 /* Validate the link local and global addresses. */
474 tx_thread_sleep(500);
475
476 /* Set up the DNS IPv6 server address. */
477 dns_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
478 dns_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
479 dns_ipv6_address.nxd_ip_address.v6[1] = 0x0000f101;
480 dns_ipv6_address.nxd_ip_address.v6[2] = 0x00000000;
481 dns_ipv6_address.nxd_ip_address.v6[3] = 0x00000107;
482
483 status = nx_dhcpv6_create_dns_address(&dhcp_server, &dns_ipv6_address);
484
485 /* Check for errors. */
486 if (status != NX_SUCCESS)
487 {
488
489 error_counter++;
490 return;
491 }
492
493 /* Note: For DUID types that do not require time, the 'duid_time' input can be
left at zero.
494 The DUID_TYPE and HW_TYPE are configurable options that are user defined in nx_dhcpv6_server.h. */
495
496 /* Set the DUID time as the start of the millennium. */
497 duid_time = SECONDS_SINCE_JAN_1_2000_MOD_32;
498 status = nx_dhcpv6_set_server_duid(&dhcp_server,
499 NX_DHCPV6_SERVER_DUID_TYPE, NX_DHCPV6_SERVER_HW_TYPE,
500 dhcp_server.nx_dhcpv6_ip_ptr -> nx_ip_arp_physical_address_msw,
501 dhcp_server.nx_dhcpv6_ip_ptr -> nx_ip_arp_physical_address_lsw,
502 duid_time);
503 if (status != NX_SUCCESS)
504 {
505 error_counter++ ;
506 return;
507 }
508
509 start_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
510 start_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
511 start_ipv6_address.nxd_ip_address.v6[1] = 0x00000f101;
512 start_ipv6_address.nxd_ip_address.v6[2] = 0x0;
513 start_ipv6_address.nxd_ip_address.v6[3] = 0x00000110;
514
515 end_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
516 end_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
517 end_ipv6_address.nxd_ip_address.v6[1] = 0x0000f101;
518 end_ipv6_address.nxd_ip_address.v6[2] = 0x00000000;
519 end_ipv6_address.nxd_ip_address.v6[3] = 0x00000120;
520
521 status = nx_dhcpv6_create_ip_address_range(&dhcp_server, &start_ipv6_address, &end_ipv6_address, &addresses_added);
522
523 if (status != NX_SUCCESS)
524 {
525 error_counter++ ;
526 return;
527 }
528
529 /* Start the NetX DHCPv6 server! */
530 status = nx_dhcpv6_server_start(&dhcp_server);
531
532 /* Check for errors. */
533 if (status != NX_SUCCESS)
534 {
535 error_counter++;
536 }
537
538 return;
539 }
540 #endif /* FEATURE_NX_IPV6 */
Figure 6. Example of the NetX Duo DHCPv6 Server