第 2 章 - 安装和使用 Azure RTOS NetX Duo DHCPv6 服务器

本章介绍了与安装、设置和使用 NetX Duo DHCPv6 服务器相关的各种问题。

产品分发

可以从我们的公共源代码存储库获取 Azure RTOS NetX Duo,网址为:https://github.com/azure-rtos/netxduo/

nxd_dhcpv6_server.h:NetX DuoDHCPv6Server 头文件

nxd_dhcpv6_server.c:NetX DuoDHCPv6Server 源文件

demo_netxduo_dhcpv6.c:NetX Duo DHCPv6 服务器演示文件

nxd_dhcpv6_server.pdf:NetX Duo DHCPv6Server 用户指南

NetX Duo DHCPv6 服务器安装

若要使用 NetX Duo DHCPv6Server API,应将前面提到的整个分发包复制到安装 NetX Duo 的目录。 例如,如果 NetX Duo 安装在“\threadx\arm7\green”目录中,则应将 nxd_dhcpv6_server.h 和 nx_dhpcv6_server.c 文件复制到该目录中 。

使用 NetX Duo DHCPv6 服务器

使用 NetX Duo DHCPv6Server API 非常简单。 基本上来说,应用程序代码必须先包含 tx_api.h 和 nx_api.h,然后包含 nx_dhcpv6-server.h,才能分别使用 ThreadX 和 NetX Duo 。 在生成过程中,应用程序还必须包含 nxd_dhcpv6_server.c。 此文件的编译方式必须与其他应用程序文件相同,并且其对象窗体必须与应用程序的文件链接起来。 这就是使用 NetX Duo DHCPv6 服务器所需的一切。

请注意,由于 DHCPv6 基于 IPv6 协议,因此必须使用 nxd_ipv6_enable 在 IP 实例上启用 IPv6。 还利用了 NetX Duo UDP 和 ICMPv6 服务。 在启动 NetX Duo DHCPv6 服务器线程任务之前,请通过调用 nx_udp_enable 启用 UDP,并通过调用 nxd_icmp_enable 启用 ICMPv6。

小型示例系统

以下小型示例使用通过虚拟“RAM”驱动程序运行的 DHCPv6 客户端和服务器,展示了使用 NetX Duo DHCPv6 服务器是多么容易。 此演示采用使用 NetX Duo 环境的单个宿主主机。

tx_application_define 创建用于发送 DHCPv6 消息的数据包池、用于客户端和服务器的线程和 IP 实例,并为客户端和服务器 IP 任务启用 UDP(DHCP 通过 UDP 运行)、IPV6、ICMP 和 ICMPv6(第 116-157 行)。

第 456 行创建了 DHCPv6 服务器。 它没有定义可选的地址拒绝或选项请求处理程序。 在服务器线程入口函数中,为服务器 IP 设置了链接本地地址服务(第 435-453 行)。

在启动 DHCPv6 服务器之前,主机应用程序创建一个服务器 DUID(第 498 行)并设置本地网络 DNS 服务器(第 483 行)。 然后,它创建可分配 IP 地址的表(第 521 行)。 有关如何在内存中存储和检索服务器表的说明,请参阅附录 D 中的“高级示例系统”。

然后即可启动 DHCPv6 服务器(第 530 行)。

有关创建和运行 NetX Duo DHCPv6 客户端的详细信息,请参阅随 DHCPv6 服务器一起分发的 nxd_dhcpv6_client.pdf 文件。


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 millenium. */
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 */

图 6。 NetX Duo DHCPv6 服务器示例