unofficial-rtos-docs

Appendix D - NetX Duo Advanced DHCPv6 server example

This is an advanced DHCPv6 Server which demonstrates saving and retrieving the Server’s IP address lease table and Client record tables from non volatile memory, as required by the RFC 3315.

In this example, the include file nxd_dhcpv6_server.h is brought in at line 7. Next, the NetX Duo DHCPv6 Server application thread is created at line 81 in the example code below. Note that the DHCPv6 control block “dhcp_server_0” was defined as a global variable at line 19 previously.

Before creating the NetX Duo DHCPv6 Server instance, the demo creates packet pool for sending DHCPv6 messages in line 84, creates an IP thread interface in line 102, and enables UDP in NetX Duo in line 116.

The successful creation of NetX Duo DHCPv6 Server in line 136 includes the the two optional callbacks function described in Chapter 1.It enables IPv6 and ICMPv6 necessary for NetX Duo to process IPv6 and DHCPv6 operations in line 162-163. Before the DHCPv6 Server thread is ready to run, the DHCPv6 server must validate its IPv6 address(167-180),and define its DHCPv6 interface in lines 208-209. The nx_dhcpv6_set_server_duid service is called to create the Server if no Server DUID has been previously created in line 266. The Server sets up an IP address range for creating a list of assignable addresses. If data is saved from a previous session, it retrieves Client records and IPv6 lease data from memory in lines 283-318. It also creates its Server DUID, or if one was previously created, retrieves the DUID data from user specified storage. This is necessary to reproduce a consistent Server DUID across reboots. Optionally the host application defines a DNS server for Clients requesting DNS server configuration.

Next, the host starts the DHCPv6Server in line 329. This creates the DHCPv6 Server UPD socket and activates NetX Duo DHCPv6 Server timers. Then the Server waits to receive Client requests. While it can service many Clients it can only process a single Client request at a time.

The remainder of the example contains host implementations for saving and retrieving Server tables of its assignable IPv6 address pool and Client records to and from non volatile memory respectively. It also contains an option handler for options requested by DHCPv6 Clients that are not supported directly by the NetX Duo DHCPv6 Server (only the DNS server option is currently supported). Lastly there is a code for demonstrating how to save and retrieve ‘non volatile time’ by which the Server keeps track of assigned IP lease expiration.

1 /* This is a small demo of the NetX Duo DHCPv6 Server for the high-performance
2 NetX Duo TCP/IP stack. */
3
4 #include     <stdio.h>
5 #include     "tx_api.h"
6 #include     "nx_api.h"
7 #include     "nxd_dhcpv6_server.h"
8
9
10 #define     DEMO_STACK_SIZE 2048
11
12
13
14 /* Define the ThreadX and NetX Duo object control blocks... */
15
16 TX_THREAD             thread_0;
17 NX_PACKET_POOL        pool_0;
18 NX_IP                 ip_0;
19 NX_DHCPV6_SERVER      dhcp_server_0;
20
21
22 /* Define the counters used in the demo application... */
23
24 ULONG                 thread_0_counter;
25 ULONG                 state_changes;
26 ULONG                 error_counter;
27
28 #define               SERVER_PRIMARY_ADDRESS IP_ADDRESS(192,2,2,66)
29
30 /* Define thread prototypes. */
31
32 void     thread_0_entry(ULONG thread_input);
33
34 /***** Substitute your ethernet driver entry function here *********/
35 void     nx_etherDriver_mcf5485(struct NX_IP_DRIVER_STRUCT *driver_req);
36
37
38 /* Define some DHCPv6 parameters. */
39
40 #define DHCPV6_IANA_ID 0xC0DEDBAD
41 #define DHCPV6_T1      NX_DHCPV6_INFINITE_LEASE
42 #define DHCPV6_T2      NX_DHCPV6_INFINITE_LEASE
43
44
45 /* Declare NetX Duo DHCPv6 Server callbacks. */
46
47 VOID dhcpv6_decline_handler(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr,
                              NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message_type);
48 VOID dhcpv6_option_request_handler(NX_DHCPV6_SERVER *dhcpv6_server_ptr, 
                                     UINT option_request, UCHAR *buffer_ptr, UINT *index);
49
50 /* Declare helper functions for the DHCPv6 Server host application. */
51 VOID dhcpv6_get_time_handler(ULONG *realtime);
52 UINT dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, 
                                      UINT *addresses_added);
53 UINT dhcpv6_restore_ip_lease_table(NX_DHCPV6_SERVER *dhcpv6_server_ptr);
54 UINT dhcpv6_restore_client_records(NX_DHCPV6_SERVER *dhcpv6_server_ptr);
55 UINT dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr);
56 UINT dhcpv6_retrieve_client_records(NX_DHCPV6_SERVER *dhcpv6_server_ptr);
57
58
59 /* Define main entry point. */
60
61 intmain()
62 {
63
64     /* Enter the ThreadX kernel. */
65     tx_kernel_enter();
66 }
67
68
69 /* Define what the initial system looks like. */
70
71 void    tx_application_define(void *first_unused_memory)
72 {
73
74 CHAR    *pointer;
75 UINT    status;
76
77     /* Setup the working pointer. */
78     pointer = (CHAR *) first_unused_memory;
79
80     /* Create the main thread. */
81     tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
82         pointer, DEMO_STACK_SIZE,
83         1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
84
85     pointer = pointer + DEMO_STACK_SIZE;
86
87     /* Initialize the NetX Duo system. */
88     nx_system_initialize();
89
90     /* Create a packet pool. */
91     status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", NX_DHCPV6_PACKET_SIZE,
                                     pointer, NX_DHCPV6_PACKET_POOL_SIZE);
92                                   pointer = pointer + NX_DHCPV6_PACKET_POOL_SIZE;
93
94     /* Check for pool creation error. */
95     if (status != NX_SUCCESS)
96     {
97         error_counter++ ;
98         return;
99     }
100
101     /* Create an IP instance. */
102     status = nx_ip_create(&ip_0, "NetX IP Instance 0", SERVER_PRIMARY_ADDRESS,
103                          0xFFFFFF00UL, &pool_0, nx_etherDriver_mcf5485,
104                          pointer, 2048, 1);
105
106     pointer = pointer + 2048;
107
108     /* Check for IP create errors. */
109     if (status != NX_SUCCESS)
110     {
111         error_counter++ ;
112         return;
113     }
114
115     /* Enable UDP traffic for sending DHCPv6 messages. */
116     status = nx_udp_enable(&ip_0);
117
118     /* Check for UDP enable errors. */
119     if (status != NX_SUCCESS)
120     {
121         error_counter++;
122         return;
123     }
124
125     /* Enable ICMP. */
126     status = nx_icmp_enable(&ip_0);
127
128     /* Check for ICMP enable errors. */
129     if (status != NX_SUCCESS)
130     {
131         error_counter++ ;
132         return;
133     }
134
135     /* Create the DHCPv6 Server. */
136     status = nx_dhcpv6_server_create(&dhcp_server_0, &ip_0, "DHCPv6 Server", &pool_0,
                                        pointer, 2048, dhcpv6_decline_handler, dhcpv6_option_request_handler);
137
138     /* Check for errors. */
139     if (status != NX_SUCCESS)
140     {
141         error_counter++;
142     }
143
144     /* Yield control to DHCPv6 threads and ThreadX. */
145     return;
146 }
147
148
149 /* Define the Server host application thread. */
150
151 void     thread_0_entry(ULONG thread_input)
152 {
153
154 UINT         status;
155 NXD_ADDRESS ipv6_address_primary, dns_ipv6_address;
156 ULONGduid_time;
157 UINTiface_index, ga_address_index;
158 UINTaddresses_added;
159
160
161     /* Make the DHCPv6 Server IPv6 and ICMPv6 enabled. */
162     nxd_ipv6_enable(&ip_0);
163     nxd_icmp_enable(&ip_0);
164
165     memset(&ipv6_address_primary,0x0, sizeof(NXD_ADDRESS));
166
167     ipv6_address_primary.nxd_ip_version = NX_IP_VERSION_V6 ;
168     ipv6_address_primary.nxd_ip_address.v6[0] = 0x20010db8;
169     ipv6_address_primary.nxd_ip_address.v6[1] = 0xf101;
170     ipv6_address_primary.nxd_ip_address.v6[2] = 0x00000000;
171     ipv6_address_primary.nxd_ip_address.v6[3] = 0x00000101;
172
173
174
175
176     /* Wait till the IP task thread has had a chance to set the device MAC address. */177
178
179     tx_thread_sleep(10);
180
181
182
183
184
185 /* Set the primary interface link local address (address index 0). This
186 will use the host MAC address to build the link local address. */
187
188     nxd_ipv6_linklocal_address_set(&ip_0, NULL);
189
196 /* Set the single homed host global IP address. */
197
198     nxd_ipv6_global_address_set(&ip_0, &ipv6_address_primary, 64);
199
200
201     tx_thread_sleep(500);
202
203
204     /* Set the server interface for DHCP communications. */
205     iface_index = 0;
206     ga_address_index = 1;
207
208     /* Set the DHCPv6 server interface to the primary interface and global address index. */
209     status = nx_dhcpv6_server_interface_set(&dhcp_server_0, iface_index, ga_address_index);
210
211     /* Wait for DHCP to assign the IP address. */
212     do
213     {
214
215         /* Check for address resolution. */
216         status = nx_ip_status_check(&ip_0, NX_IP_ADDRESS_RESOLVED, (ULONG *)
                                        &status, 100000);
217
218         /* Check status. */
219         if (status)
220         {
221
222             tx_thread_sleep(20);
223         }
224
225     } while (status != NX_SUCCESS);
226
227     dns_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
228     dns_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
229     dns_ipv6_address.nxd_ip_address.v6[1] = 0x0000f101;
230     dns_ipv6_address.nxd_ip_address.v6[2] = 0x00000000;
231     dns_ipv6_address.nxd_ip_address.v6[3] = 0x00000107;
232
233     status = nx_dhcpv6_create_dns_address(&dhcp_server_0, &dns_ipv6_address);
234
235     /* Check for errors. */
236     if (status != NX_SUCCESS)
237     {
238
239         error_counter++;
240         return;
241     }
242
243     /* Set the server DUID before starting the DHCPv6 server. You will also need to set the
244        Server DUID if you are restoring Client data from non volatile memory.
245
246        This demo will create a server DUID of the link layer time DUID type.
247
248        Note #1: The RFC 3315 Sect 9.2 recommends link layer time DUID type over link layer
249        DUID type to minimize the chances of 'collisions' or identical DUIDs between hosts,
           particularly clients.
250
251        Note #2: If the client or server host is rebooting, RFC 3315 Sect 9.2 requires the
252        host retrieve its previously created DUID data rather than create one from new data.
253
254        For a Link layer time DUID, retrieve a time value. If the DHCPv6 server has not
255        created a server DUID previously, this function should provide a new value;        
           otherwise this function must retrieve the time data used in the previously created server DUID. For link layer and enterprise type DUIDs, the 'duid_time' data is not
           necessary. */
259        dhcpv6_get_time_handler(&duid_time);
260
261
262     /* For DUID types that do not require time, the 'duid_time' input can be left at zero.
263        The DUID_TYPE and HW_TYPE are configurable options that are user defined in
           nxd_dhcpv6_server.h. */
264
265
266     status = nx_dhcpv6_set_server_duid(&dhcp_server_0,
267                                       NX_DHCPV6_SERVER_DUID_TYPE, NX_DHCPV6_SERVER_HW_TYPE,
268                                       dhcp_server_0.nx_dhcpv6_ip_ptr >>
                                          nx_ip_arp_physical_address_msw,
269                                       dhcp_server_0.nx_dhcpv6_ip_ptr >>
                                          nx_ip_arp_physical_address_lsw,
270                                       duid_time);
271     if (status != NX_SUCCESS)
272     {
273         error_counter++ ;
274         return;
275     }
276
277
278     /* The next step is to set up the server IP lease and Client record tables. If no
279        previous data exists, the host application only needs to create an IP address range
280        of assignable IP addresses, and set the size of the tables, NX_DHCPV6_MAX_CLIENTS
281        and NX_DHCPV6_MAX_LEASES in nxd_dhcpv6_server.h. */
282
283 #ifndef RESTORE_SERVER_DATA
284
285     /* Create the ip address table on the primary server network interface. */
286     status = dhcpv6_create_ip_address_range(&dhcp_server_0, &addresses_added);
287
288     if (status != NX_SUCCESS)
289     {
290
291         error_counter++;
292         return;
293     }
294
295 #else
296
297     /* RFC 3315 requires that DHCPv6 servers be able to store and retrieve lease data to 
           and from non-volatile memory so that DHCPv6 server may remain uninterrupted across server reboots. */
299     status = dhcpv6_restore_ip_lease_table(&dhcp_server_0);
300
301     if (status != NX_SUCCESS)
302     {
303
304         error_counter++;
305         return;
306     }
307
308     status = dhcpv6_restore_client_records(&dhcp_server_0);
309
310     if (status != NX_SUCCESS)
311     {
312
313         error_counter++;
314         return;
315     }
316
317
318 #endif /* RESTORE_SERVER_DATA */
319
320     /*Check for error. */
321     if (status != NX_SUCCESS)
322     {
323
324         error_counter++;
325         return;
326     }
327
328     /* Start the NetX Duo DHCPv6 server! */
329     status = nx_dhcpv6_server_start(&dhcp_server_0);
330
331     /* Check for errors. */
332     if (status != NX_SUCCESS)
333     {
334         error_counter++;
335     }
336
337     return;
338 }
339
340 /* Simulate a handler with access to a real time clock and non volatile memory storage. 
       This service is required for a link layer time DUID to create a time value as part of
341    the DUID. A default value is provided below. The time value serves
342    no actual function, but increases the chances of a unique host DUID.
343
344    It is the host's responsibility to save the 'time' data created for the server DUID to
       memory. The DHCPv6 server should always use a previously created its server DUID as per
345    RFC 3315 Sect. 9.2. */
346 VOID dhcpv6_get_time_handler(ULONG *realtime)
347 {
348
349
350     /* Check if the DHCPv6 server has previously created a DUID. If so
351     return this time value to the host application. */
352     /*********** insert your application logic here **************/
353
354     /* Otherwise create time data. One can use a random number incremented
355     to the number of seconds since JAN 1, 2000 to
356     create a unique time value. */
357     *realtime = SECONDS_SINCE_JAN_1_2000_MOD_32;
358
359     return;
360 }
361
362
363 /* Create an IP address lease table based on from a range of available addresses. */
364 UINT dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr,
*UINT *addresses_added)
365 {
366
367 UINT status;
368 NXD_ADDRESS start_ipv6_address;
369 NXD_ADDRESS end_ipv6_address;
370
371
372     start_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
373     start_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
374     start_ipv6_address.nxd_ip_address.v6[1] = 0x00000f101;
375     start_ipv6_address.nxd_ip_address.v6[2] = 0x0;
376     start_ipv6_address.nxd_ip_address.v6[3] = 0x00000110;
377
378     end_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6 ;
379     end_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
380     end_ipv6_address.nxd_ip_address.v6[1] = 0x0000f101;
381     end_ipv6_address.nxd_ip_address.v6[2] = 0x00000000;
382     end_ipv6_address.nxd_ip_address.v6[3] = 0x00000120;
383
384     status = nx_dhcpv6_create_ip_address_range(dhcpv6_server_ptr, &start_ipv6_address,
                                                  &end_ipv6_address, addresses_added);
385
386     return status;
387
388 }
389
390 /* Demonstrate how to use NetX Duo DHCPv6 Server API to upload data from memory
391 to the DHCPv6 server's IP lease tables. */
392 UINT dhcpv6_restore_ip_lease_table(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
393 {
394
395 NXD_ADDRESS  next_ipv6_address;
396 UINTi;
397 UINT         status;
398
399
400     /* Set the starting IP address. */
401     next_ipv6_address.nxd_ip_version = 6;
402     next_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
403     next_ipv6_address.nxd_ip_address.v6[1] = 0x00000f101;
404     next_ipv6_address.nxd_ip_address.v6[2] = 0x0;
405     next_ipv6_address.nxd_ip_address.v6[3] = 0x00000110;
406
407
408     /* Copy the 'lease data' to the server table. */
409     for (i = 0; i< NX_DHCPV6_MAX_LEASES; i++)
410     {
411
412         /* These are assigned address leases. */
413
414         status = nx_dhcpv6_add_ip_address_lease(dhcpv6_server_ptr, i, &next_ipv6_address,
                     NX_DHCPV6_DEFAULT_T1_TIME, NX_DHCPV6_DEFAULT_T2_TIME,
415                  X_DHCPV6_DEFAULT_PREFERRED_TIME, NX_DHCPV6_DEFAULT_VALID_TIME);
416
417     if (status != NX_SUCCESS)
418         return status;
419
420         /* Simulate the next IP address in the table. */
421         next_ipv6_address.nxd_ip_address.v6[3]++;
422     }
423
424     return NX_SUCCESS;
425 }
426
427 /* Demonstrate how to use NetX Duo DHCPv6 Server API to download data to local memory and
428 eventually nonvolatile memory from the DHCPv6 server's IP lease tables. This might be
called after the a certain duration of operation and after stopping Server task (e.g.
before rebooting or for making a backup).*/
429 UINT     dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
430 {
431
432 NXD_ADDRESS   next_ipv6_address;
433 ULONG         T1, T2, valid_lifetime, preferred_lifetime;
434 UINTi;
435 UINT          status;
436
437
438
439
440
442     for (i = 0; i< NX_DHCPV6_MAX_LEASES; i++)
443     {
444
445         T1 = 0;
446         T2 = 0;
447         valid_lifetime = 0;
448         preferred_lifetime = 0;
449         memset(&next_ipv6_address, 0, sizeof(NXD_ADDRESS));
450
451         /* Get the next lease from the table. */
452         status = nx_dhcpv6_retrieve_ip_address_lease(dhcpv6_server_ptr, i,
                     &next_ipv6_address, &T1, &T2, &preferred_lifetime, &valid_lifetime);
453
454         if (status != NX_SUCCESS)
455             return status;
456
457         /* At this point the host application would store this record to NV memory. */
458     }
459
460     return NX_SUCCESS;
461 }
462
463 /* Demonstrate how to use NetX Duo DHCPv6 Server API to upload data from memory
464 to the DHCPv6 server's client record tables. */
465 UINT dhcpv6_restore_client_records(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
466 {
467
468 UINTi;
469 UINT     status;
470
471 /* Create data to simulate client records stored in memory. */
472 NXD_ADDRESS client_ipv6_address;
473 UINTduid_type = 1;
474 UINTduid_hardware = NX_DHCPV6_HW_TYPE_IEEE_802;
475 ULONGmessage_xid = 0xabcd;
476 UINTduid_time = 0x1234567;
477 ULONGphysical_address_msw = 0x01;
478 ULONGphysical_address_lsw = 0x02030405;
479 ULONGIP_lifetime_time_accrued = 200000; /* lease time accrued (ticks) */
480 ULONGvalid_lifetime = 300000; /* expiration on the lease (ticks) */
481 ULONGenterprise_number = 0xaaaa;
482 UCHARprivate_id[8];
483 UINT     length;
484
485
486     /* Set the Client IP address. */
487     client_ipv6_address.nxd_ip_version = 6;
488     client_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
489     client_ipv6_address.nxd_ip_address.v6[1] = 0x00000f101;
490     client_ipv6_address.nxd_ip_address.v6[2] = 0x0;
491     client_ipv6_address.nxd_ip_address.v6[3] = 0x00000110;
492
493
494     /* Copy the 'lease data' to the server table. */
495     for (i = 0; i< 10; i++)
496     {
497         /* Simulate a Client record with a vendor assigned DUID. */
498         if (i == 0)
499         {
500             duid_type = NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED;
501
502             memcpy(&private_id[0], "Corp_XYZ", sizeof("Corp_XYZ"));
503             length = sizeof("Corp_XYZ") + 4;
504             status = nx_dhcpv6_add_client_record(dhcpv6_server_ptr, i, message_xid,
                         &client_ipv6_address, NX_DHCPV6_STATE_BOUND, IP_lifetime_time_accrued,
                         valid_lifetime, duid_type, duid_hardware, physical_address_msw,
                         physical_address_lsw, duid_time, enterprise_number,
506                      &private_id[0], length);
507         }
508         /* Simulate client record with a link layer DUID. */
509         else
510         {
511                 status = nx_dhcpv6_add_client_record(dhcpv6_server_ptr, i, message_xid,
                             &client_ipv6_address, NX_DHCPV6_STATE_BOUND, IP_lifetime_time_accrued,
512                          valid_lifetime, duid_type, duid_hardware, physical_address_msw,
                             physical_address_lsw, duid_time, 0, NX_NULL, 0);
513         }
515
516         /* Check for error. */
517         if (status != NX_SUCCESS)
518         {
519
520             /* Check if the Client address is found in the IP lease table. */
521             if (status == NX_DHCPV6_ADDRESS_NOT_FOUND)
522             {
523
524                 /* It is not. Client state should be set to unbound/init.*/
525             }
526             else
527             {
528
529                 /* Either the table is full or the index exceeds the bounds of the table. */
530                 return status;
531             }
532         }
533
534         /* Simulate the Client IP address in the table. Leave all other client 'data' the
            same for the next record we'll 'restore'. */
535         client_ipv6_address.nxd_ip_address.v6[3]++;
536         physical_address_lsw++;
537         message_xid++;
538     }
539
540     return NX_SUCCESS;
541 }
542
543 /* Demonstrate how to use NetX Duo DHCPv6 Server API to download data to local memory and
544 eventually nonvolatile memory from the DHCPv6 server's client record tables. */
545
546 UINT dhcpv6_retrieve_client_records(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
547 {
548
549 UINTi;
550 UINT         status;
551 NXD_ADDRESS  client_ipv6_address;
552 UINTduid_type;
553 UINTduid_hardware;
554 ULONGmessage_xid;
555 ULONGduid_time;
556 ULONGphysical_address_msw;
557 ULONGphysical_address_lsw;
558 ULONGIP_lifetime_time_accrued; /* lease time accrued (ticks) */
559 ULONGvalid_lifetime; /* expiration on the lease (ticks) */
560 ULONGduid_vendor_number;
561 UCHARprivate_id[8];
562 UINT          length;
563 UINTclient_state;
564
565
566     for (i = 0; i< 100; i++)
567     {
568
569         memset(&client_ipv6_address, 0,sizeof(NXD_ADDRESS));
570
571         status = nx_dhcpv6_retrieve_client_record(dhcpv6_server_ptr, i, &message_xid,
                     &client_ipv6_address, &client_state, &IP_lifetime_time_accrued,
572                  &valid_lifetime, &duid_type, &duid_hardware, &physical_address_msw,
573                  &physical_address_lsw, &duid_time, &duid_vendor_number, &private_id[0], 
                     &length);
574
575         if (status != NX_SUCCESS)
576         {
577             /* The host application should handle error status returns depending on
578             the specific error code. See the user guide for error returns for
579             this service. */
580         }
581
582     }
583
584     return NX_SUCCESS;
586 }
587
589 /* This is an optional callback for NetX DHCPv6 server to notify the host application
590 that it has received either a DECLINE or RELEASE address from a Client. */
591
592 VOID dhcpv6_decline_handler(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT
                               *dhcpv6_client_ptr, UINT message_type)
593 {
594
595     switch (message_type)
596     {
597         case NX_DHCPV6_MESSAGE_TYPE_DECLINE:
598
599
600             /* Host application handles a declined address. The Server will
601             mark the address as assigned elsewhere. Any other processing
602             is left to the host application. */
603
604         break;
605
606         case NX_DHCPV6_MESSAGE_TYPE_RELEASE:
607
608             /* Host application handles a released address. The Server will
609             mark the released IP address as available for lease to other
610             clients. Any other processing is left to the host application. */
611
612         break;
613
614         default:
615
616             /* Unhandled message type */
617             error_counter++;
618         break;
619     }
620
621     return;
622 }
623
624 /* This is an optional DHCPv6 server callback to handle client option request options. */
625 VOID dhcpv6_option_request_handler(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT
                                      option_request, UCHAR *buffer_ptr, UINT *index)
626 {
627
628 UCHARoption_length = 10;
629 UCHARoption_code = 24;
630 ULONGmessage_word;
631
632
633     if (option_request == 24)
634     {
635
636         message_word = option_code<< 16;
637         message_word |= option_length;
638
639         /* Adjust for endianness. */
640         NX_CHANGE_ULONG_ENDIAN(message_word);
641
642         /* Copy the option request option header to the packet. */
643         memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG));
644         *index += sizeof(ULONG);
645
646         /* Copy the code for domain search list. */
647         *(buffer_ptr + *index) = 0x04;
648         (*index)++;
649
650         /* Adjusting for endianness is an exercise left for the reader. */
651         memcpy(buffer_ptr + *index, "abc.com", sizeof("abc.com"));
652         (*index) += sizeof("abc.com");
653     }
654     /* else unknown option; just return; no need to adjust buffer pointers. */
655
656     return;
657 }

Figure 6. Advanced NetX Duo DHCPv6 Server Application