附录 D - Azure RTOS NetX Duo 高级 DHCPv6 服务器示例

这是一种高级 DHCPv6 服务器,它演示了如何根据 RFC 3315 的要求,从非易失性内存保存和检索服务器的 IP 地址租用表和客户端记录表。

在此示例中,在第 7 行中引入了 include 文件 nxd_dhcpv6_server.h。 接下来,在下面的示例代码中,在第 81 行创建了 NetX Duo DHCPv6 服务器应用程序线程。 请注意,DHCPv6 控制块“dhcp_server_0”以前在第 19 行定义为全局变量。

在创建 NetX Duo DHCPv6 服务器实例之前,此演示在第 84 行创建用于发送 DHCPv6 消息的数据包池,在第 102 行创建 IP 线程接口,在第 116 行在 NetX Duo 中启用 UDP。

在第 136 行成功创建的 NetX Duo DHCPv6 服务器包括第 1 章中描述的两个可选回调函数。它在 162-163 行启用了 NetX Duo 处理 IPv6 和 DHCPv6 操作所需的 IPv6 和 ICMPv6。 在 DHCPv6 服务器线程准备好运行之前,DHCPv6 服务器必须验证其 IPv6 地址(167-180 行),并定义其 DHCPv6 接口(208-209 行)。 如果之前未在第 266 行中创建任何服务器 DUID,则调用 nx_dhcpv6_set_server_duid 服务来创建服务器。 服务器设置一个 IP 地址范围来创建可分配地址的列表。 如果在前面的会话中保存了数据,则它将从内存中检索客户端记录和 IPv6 租用数据(第 283-318 行)。 它还会创建其服务器 DUID。如果以前创建了一个,则会从用户指定的存储中检索 DUID 数据。 这是在重启后重现一致的服务器 DUID 所必需的。 (可选)主机应用程序为请求 DNS 服务器配置的客户端定义 DNS 服务器。

接下来,主机启动 DHCPv6Server(第 329 行)。 这会创建 DHCPv6 服务器 UPD 套接字,并激活 NetX Duo DHCPv6 服务器计时器。 然后,服务器等待接收客户端请求。 尽管它可以为多个客户端提供服务,但每次只能处理一个客户端请求。

本示例的剩余部分包含的主机实现用于将可分配的 IPv6 地址池的服务器表和客户端记录分别保存到非易失性内存以及从中检索它们。 它还包含一个选项处理程序,用于处理 DHCPv6 客户端请求的但 NetX Duo DHCPv6 服务器不能直接支持的选项(当前仅支持 DNS 服务器选项)。 最后,还有一段用于演示如何保存和检索“非易失时间”的代码。服务器需要根据该时间来跟踪分配的 IP 租用的到期情况。

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         /* Simluate 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 }

图 6。 高级 NetX Duo DHCPv6 服务器应用程序