1 /* This is a small demo of the NetX Duo DHCPv6 Client for the high-performance NetX Duo stack.  */
2 
3 #include    <stdio.h>
4 #include   "tx_api.h"
5 #include   "nx_api.h"
6 #include   "nxd_dhcpv6_client.h"
7 
8 #ifdef FEATURE_NX_IPV6
9 #define     DEMO_STACK_SIZE         2048
10 
11 /* Set the client address, and request these address from DHCPv6 Server.  */
12 /*
13 #define     NX_DHCPV6_REQUEST_IA_ADDRESS
14 */
15 
16 /* Set the list of DHCPv6 option data (timezone, DNS server, timer server, domain name)to get from the DHCPv6 server.  */
17 
18 #define     NX_DHCPV6_REQUEST_OPTION
19 
20 
21 /* Add the fully qualified domain name to request whether the DHCPv6 server SHOULD or SHOULD NOT perform the AAAA RR or DNS updates.  */
22 
23 #define     NX_DHCPV6_REQUEST_FQDN_OPTION
24 
25 
26 /* Define the ThreadX and NetX object control blocks...  */
27 
28 NX_PACKET_POOL          pool_0;
29 TX_THREAD               thread_client;
30 NX_IP                   client_ip;
31 
32 /* Define the Client and Server instances. */
33 
34 NX_DHCPV6               dhcp_client;
35 
36 /* Define the error counter used in the demo application...  */
37 ULONG                   error_counter;
38 CHAR                    *pointer;
39 
40 /* Define thread prototypes.  */
41 void    thread_client_entry(ULONG thread_input);
42 
43 /***** Substitute your ethernet driver entry function here *********/
44 extern VOID    _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);
45 
46 /* Declare DHCPv6 Client callbacks */
47 VOID dhcpv6_state_change_notify(NX_DHCPV6 *dhcpv6_ptr, UINT old_state, UINT new_state);
48 VOID dhcpv6_server_error_handler(NX_DHCPV6 *dhcpv6_ptr, UINT op_code, UINT status_code, UINT message_type);
49 
50 /* Set up globals for tracking changes to DHCPv6 Client from callback services. */
51 UINT state_changes = 0;
52 UINT address_expired = 0;
53 UINT address_failed_dad = 0;
54 UINT bound_addresses = 0;
55 UINT address_not_assigned = 0;
56 UINT server_errors = 0;
57 
58 /* Define some DHCPv6 parameters. */
59 
60 #define DHCPV6_IANA_ID      0xABCDEFAB
61 #define DHCPV6_T1           NX_DHCPV6_INFINITE_LEASE
62 #define DHCPV6_T2           NX_DHCPV6_INFINITE_LEASE
63 #define DHCPV6_RENEW_TIME   NX_DHCPV6_INFINITE_LEASE
64 #define DHCPV6_REBIND_TIME  NX_DHCPV6_INFINITE_LEASE
65 #define PACKET_PAYLOAD      500
66 #define PACKET_POOL_SIZE    (5*PACKET_PAYLOAD)
67 
68 /* Define main entry point.  */
69 
main()70 int main()
71 {
72 
73     /* Enter the ThreadX kernel.  */
74     tx_kernel_enter();
75 }
76 
77 
78 /* Define what the initial system looks like.  */
79 
tx_application_define(void * first_unused_memory)80 void    tx_application_define(void *first_unused_memory)
81 {
82 
83 UINT    status;
84 
85     /* Setup the working pointer.  */
86     pointer =  (CHAR *) first_unused_memory;
87 
88     /* Create the Client thread.  */
89     status = tx_thread_create(&thread_client, "Client thread", thread_client_entry, 0,
90                               pointer, DEMO_STACK_SIZE, 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
91 
92     /* Check for IP create errors.  */
93     if (status)
94     {
95         error_counter++;
96         return;
97     }
98 
99     pointer =  pointer + DEMO_STACK_SIZE;
100 
101     /* Initialize the NetX system.  */
102     nx_system_initialize();
103 
104     /* Create a packet pool.  */
105     status =  nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 1024,  pointer, PACKET_POOL_SIZE);
106 
107     pointer = pointer + PACKET_POOL_SIZE;
108 
109     /* Check for pool creation error.  */
110     if (status)
111     {
112         error_counter++;
113         return;
114     }
115 
116     /* Create a Client IP instance.  */
117     status = nx_ip_create(&client_ip, "Client IP", IP_ADDRESS(0, 0, 0, 0),
118                           0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
119                           pointer, 2048, 1);
120 
121     pointer =  pointer + 2048;
122 
123     /* Check for IP create errors.  */
124     if (status)
125     {
126         error_counter++;
127         return;
128     }
129 
130     /* Enable UDP traffic for sending DHCPv6 messages.  */
131     status =  nx_udp_enable(&client_ip);
132 
133     /* Check for UDP enable errors.  */
134     if (status)
135     {
136         error_counter++;
137         return;
138     }
139 
140     /* Enable ICMP.  */
141     status =  nx_icmp_enable(&client_ip);
142 
143     /* Check for ICMP enable errors.  */
144     if (status)
145     {
146         error_counter++;
147         return;
148     }
149 
150     /* Create the DHCPv6 Client. */
151     status =  nx_dhcpv6_client_create(&dhcp_client, &client_ip, "DHCPv6 Client",
152                                       &pool_0, pointer, 2048, dhcpv6_state_change_notify,
153                                       dhcpv6_server_error_handler);
154 
155     /* Check for errors.  */
156     if (status)
157     {
158         error_counter++;
159         return;
160     }
161 
162     /* Update the stack pointer because we need it again. */
163     pointer = pointer + 2048;
164 
165     /* Yield control to DHCPv6 threads and ThreadX. */
166     return;
167 }
168 
169 
170 /* Define the Client host application thread. */
171 
thread_client_entry(ULONG thread_input)172 void    thread_client_entry(ULONG thread_input)
173 {
174 
175 UINT        status;
176 ULONG       T1, T2;
177 UINT        address_count;
178 UINT        address_index = 0;
179 NXD_ADDRESS valid_ipv6_address;
180 ULONG       preferred_lifetime;
181 ULONG       valid_lifetime;
182 UINT        ia_count = 1;
183 
184 #ifdef NX_DHCPV6_REQUEST_IA_ADDRESS
185 NXD_ADDRESS ipv6_address;
186 #endif
187 
188 #ifdef NX_DHCPV6_REQUEST_OPTION
189 UCHAR       buffer[200];
190 NXD_ADDRESS dns_server;
191 #endif
192 
193 #ifdef NX_DHCPV6_CLIENT_RESTORE_STATE
194 ULONG       current_time;
195 ULONG       elapsed_time;
196 NX_DHCPV6_CLIENT_RECORD dhcpv6_client_record;
197 #endif
198 
199     NX_PARAMETER_NOT_USED(thread_input);
200 
201     state_changes = 0;
202 
203     /* Establish the link local address for the host. The RAM driver creates
204        a virtual MAC address of 0x1122334456. */
205     status = nxd_ipv6_address_set(&client_ip, 0, NX_NULL, 10, NULL);
206 
207     if (status)
208     {
209         error_counter++;
210         return;
211     }
212 
213     /* Let NetX Duo get initialized. */
214     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
215 
216     /* Enable the Client IP for IPv6 and ICMPv6 services. */
217     nxd_ipv6_enable(&client_ip);
218     nxd_icmp_enable(&client_ip);
219 
220     /* Create a Link Layer Plus Time DUID for the DHCPv6 Client. Set time ID field
221        to NULL; the DHCPv6 Client API will supply one. */
222     status = nx_dhcpv6_create_client_duid(&dhcp_client, NX_DHCPV6_DUID_TYPE_LINK_TIME,
223                                           NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET, 0);
224 
225     if (status != NX_SUCCESS)
226     {
227         error_counter++;
228         return;
229     }
230 
231     /* Create the DHCPv6 client's Identity Association (IA-NA) now.
232 
233        Note that if this host had already been assigned in IPv6 lease, it
234        would have to use the assigned T1 and T2 values in loading the DHCPv6
235        client with an IANA block.
236     */
237     status = nx_dhcpv6_create_client_iana(&dhcp_client, DHCPV6_IANA_ID, DHCPV6_T1,  DHCPV6_T2);
238 
239     if (status != NX_SUCCESS)
240     {
241         error_counter++;
242         return;
243     }
244 
245 #ifdef NX_DHCPV6_REQUEST_IA_ADDRESS
246     memset(&ipv6_address,0x0, sizeof(NXD_ADDRESS));
247     ipv6_address.nxd_ip_version = NX_IP_VERSION_V6;
248     ipv6_address.nxd_ip_address.v6[0] = 0x3ffe0501;
249     ipv6_address.nxd_ip_address.v6[1] = 0xffff0100;
250     ipv6_address.nxd_ip_address.v6[2] = 0x00000000;
251     ipv6_address.nxd_ip_address.v6[3] = 0x0000abcd;
252 
253     /* Create an IA address option.
254         Note that if this host had already been assigned in IPv6 lease, it
255         would have to use the assigned IPv6 address, preferred and valid lifetime
256         values in loading the DHCPv6 Client with an IA block.
257     */
258     status = nx_dhcpv6_add_client_ia(&dhcp_client, &ipv6_address,DHCPV6_RENEW_TIME, DHCPV6_REBIND_TIME);
259 
260     if (status != NX_SUCCESS)
261     {
262         error_counter++;
263         return;
264     }
265 
266     /* If the DHCPv6 Client is configured for a maximum number of IA addresses
267        greater than 1, we can add another IA address if the device requires
268        multiple global IPv6 addresses.  */
269     if(NX_DHCPV6_MAX_IA_ADDRESS >= 2)
270     {
271         memset(&ipv6_address,0x0, sizeof(NXD_ADDRESS));
272         ipv6_address.nxd_ip_version = NX_IP_VERSION_V6;
273         ipv6_address.nxd_ip_address.v6[0] = 0x3ffe0501;
274         ipv6_address.nxd_ip_address.v6[1] = 0xffff0100;
275         ipv6_address.nxd_ip_address.v6[2] = 0x00000000;
276         ipv6_address.nxd_ip_address.v6[3] = 0x00001234;
277 
278         /* Add another  IA address option.  */
279         status = nx_dhcpv6_add_client_ia(&dhcp_client, &ipv6_address, DHCPV6_RENEW_TIME, DHCPV6_REBIND_TIME);
280 
281         if (status != NX_SUCCESS)
282         {
283             error_counter++;
284             return;
285         }
286     }
287 #endif /* NX_DHCPV6_REQUEST_IA_ADDRESS  */
288 
289 #ifdef NX_DHCPV6_REQUEST_OPTION
290     /* Set the list of DHCPv6 option data to get from the DHCPv6 server if needed. */
291     nx_dhcpv6_request_option_timezone(&dhcp_client, NX_TRUE);
292     nx_dhcpv6_request_option_DNS_server(&dhcp_client, NX_TRUE);
293     nx_dhcpv6_request_option_time_server(&dhcp_client, NX_TRUE);
294     nx_dhcpv6_request_option_domain_name(&dhcp_client, NX_TRUE);
295 #endif /* NX_DHCPV6_REQUEST_OPTION */
296 
297 
298 #ifdef NX_DHCPV6_REQUEST_FQDN_OPTION
299     /* Set the DHCPv6 Client FQDN option.
300        operation: NX_DHCPV6_CLIENT_DESIRES_UPDATE_AAAA_RR         DHCPv6 Client choose to updating the FQDN-to-IPv6 address mapping for FQDN and address(es) used by the client.
301                   NX_DHCPV6_CLIENT_DESIRES_SERVER_DO_DNS_UPDATE   DHCPv6 Client choose to updating the FQDN-to-IPv6 address mapping for FQDN and address(es) used by the client to the server.
302                   NX_DHCPV6_CLIENT_DESIRES_NO_SERVER_DNS_UPDATE   DHCPv6 Client choose to request that the server perform no DNS updatest on its behalf.  */
303     nx_dhcpv6_request_option_FQDN(&dhcp_client, "DHCPv6-Client", NX_DHCPV6_CLIENT_DESIRES_UPDATE_AAAA_RR);
304 #endif /* NX_DHCPV6_REQUEST_FQDN_OPTION */
305 
306     /* Start up the NetX DHCPv6 Client thread task. */
307     status =  nx_dhcpv6_start(&dhcp_client);
308 
309     /* Check for errors. */
310     if (status != NX_SUCCESS)
311     {
312 
313         error_counter++;
314         return;
315     }
316 
317     /* Start the DHCPv6 by sending a Solicit message out on the network. */
318     status = nx_dhcpv6_request_solicit(&dhcp_client);
319 
320     /* Check status.  */
321     if (status != NX_SUCCESS)
322     {
323 
324         error_counter++;
325         return;
326     }
327 
328     /* Is the DHCPv6 Client request for address assignment successfully started? */
329     if (status == NX_SUCCESS)
330     {
331 
332         /* If Duplicate Address Detection (DAD) is enabled in NetX Duo, e.g. #NX_DISABLE_IPV6_DAD
333            not defined, allow time for NetX Duo to verify the address is unique on our network.
334          */
335         tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
336 
337         /* Check the bound address.  */
338         if (bound_addresses != ia_count)
339         {
340 
341             /* Attempt to find out why DHCPv6 failed, where...*/
342 
343             if (server_errors > 0)
344             {
345                 /* Actually you would compare server_error count with number of IA's added
346                    to determine if any addresses were assigned. */
347                 printf("Server error, not all address assigned\n");
348             }
349 
350             if (address_not_assigned > 0)
351             {
352                 /* Actually you would compare address not assigned count with number of IA's added
353                    to determine if any addresses were assigned. */
354 
355                 printf("No servers responded to some or all of our IAs\n");
356             }
357 
358         }
359 
360         /* Regardless if the DHCPv6 Client achieved a bound state, check for DAD
361            failures. */
362         if (address_failed_dad > 0)
363         {
364             /* Actually you would compare failed dad count with number of IA's added
365                to determine if any addresses were assigned. */
366 
367             printf("Some or all of our IAs failed DAD\n");
368 
369         }
370 
371         /* Successfully assigned IPv6 addresses! */
372 
373         /* Get the count of valid IPv6 address obtained by DHCPv6.  */
374         status = nx_dhcpv6_get_valid_ip_address_count(&dhcp_client, &address_count);
375 
376         /* Check status.  */
377         if (status != NX_SUCCESS)
378         {
379             error_counter++;
380         }
381 
382         /* Get the IPv6 address and related lifetimes by address index. This index is the
383            index into the DHCPv6 Client address table.  Not to be confused with the IP
384            instance address table! */
385         status = nx_dhcpv6_get_valid_ip_address_lease_time(&dhcp_client, address_index,
386                                                            &valid_ipv6_address, &preferred_lifetime,
387                                                            &valid_lifetime);
388 
389         /* Check status.  */
390         if (status != NX_SUCCESS)
391         {
392             error_counter++;
393         }
394 
395         /* Get the IANA options for when to start renew/rebind requests. These time
396            parameters are the same for all IPv6 addresses assigned in the Client
397            e.g. IANA returned from Server.  */
398         status = nx_dhcpv6_get_iana_lease_time(&dhcp_client, &T1, &T2);
399 
400         /* Check status.  */
401         if (status != NX_SUCCESS)
402         {
403             error_counter++;
404         }
405 
406         /*****************************************************************************/
407         /* These are 'legacy' DHCPv6 services and are for the most part identical to the services
408            above except they default to the primary global IPv6 address regardless if the
409            Client was assigned more than one global IPv6 address. */
410 
411         /* Now check the assigned lease times. */
412         status = nx_dhcpv6_get_lease_time_data(&dhcp_client, &T1, &T2,
413                                                &preferred_lifetime, &valid_lifetime);
414 
415         /* Check status.  */
416         if (status != NX_SUCCESS)
417         {
418             error_counter++;
419         }
420 
421         /* Get the IP address.  */
422         status = nx_dhcpv6_get_IP_address(&dhcp_client, &valid_ipv6_address);
423 
424         /* Check status.  */
425         if (status != NX_SUCCESS)
426         {
427             error_counter++;
428         }
429 
430         /* Bound state.  */
431 
432 #ifdef NX_DHCPV6_CLIENT_RESTORE_STATE
433 
434         /* Get the DHCPv6 Client record.  */
435         nx_dhcpv6_client_get_record(&dhcp_client, &dhcpv6_client_record);
436 
437         /* Delete DHCPv6 instance.  */
438         nx_dhcpv6_client_delete(&dhcp_client);
439 
440         /* Delete IP instance.  */
441         status = nx_ip_delete(&client_ip);
442 
443         /* Check for error.  */
444         if (status)
445         {
446             error_counter++;
447             return;
448         }
449 
450         /* Create a Client IP instance.  */
451         status = nx_ip_create(&client_ip, "Client IP", IP_ADDRESS(0, 0, 0, 0),
452                               0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
453                               pointer, 2048, 1);
454 
455         pointer =  pointer + 2048;
456 
457         /* Check for IP create errors.  */
458         if (status)
459         {
460             error_counter++;
461             return;
462         }
463 
464         /* Enable UDP traffic for sending DHCPv6 messages.  */
465         status =  nx_udp_enable(&client_ip);
466 
467         /* Check for UDP enable errors.  */
468         if (status)
469         {
470             error_counter++;
471             return;
472         }
473 
474         /* Enable ICMP.  */
475         status =  nx_icmp_enable(&client_ip);
476 
477         /* Check for ICMP enable errors.  */
478         if (status)
479         {
480             error_counter++;
481             return;
482         }
483 
484         /* Enable the Client IP for IPv6 and ICMPv6 services. */
485         status = nxd_ipv6_enable(&client_ip);
486         status += nxd_icmp_enable(&client_ip);
487 
488         /* Check for IPv6 and ICMPv6 enable errors.  */
489         if (status)
490         {
491             error_counter++;
492             return;
493         }
494 
495         /* Establish the link local address for the host. The RAM driver creates
496            a virtual MAC address of 0x1122334456. */
497         status = nxd_ipv6_address_set(&client_ip, 0, NX_NULL, 10, NULL);
498 
499         if (status)
500         {
501             error_counter++;
502             return;
503         }
504 
505         /* If Duplicate Address Detection (DAD) is enabled in NetX Duo, e.g. #NX_DISABLE_IPV6_DAD
506            not defined, allow time for NetX Duo to verify the address is unique on our network.
507          */
508         tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
509 
510         /* Create the DHCPv6 Client. */
511         status =  nx_dhcpv6_client_create(&dhcp_client, &client_ip, "DHCPv6 Client",
512                                           &pool_0, pointer, 2048, dhcpv6_state_change_notify,
513                                           dhcpv6_server_error_handler);
514 
515         /* Check for errors.  */
516         if (status)
517         {
518             error_counter++;
519             return;
520         }
521 
522         /* Update the stack pointer because we need it again. */
523         pointer = pointer + 2048;
524 
525         /* Restore the DHCPv6 record.  */
526         nx_dhcpv6_client_restore_record(&dhcp_client, &dhcpv6_client_record, 5);
527 
528         /* Resume the DHCPv6 service.  */
529         nx_dhcpv6_resume(&dhcp_client);
530 #endif
531 
532 
533 #ifdef NX_DHCPV6_REQUEST_OPTION
534 
535         /* Get the DNS Server address.  */
536         nx_dhcpv6_get_DNS_server_address(&dhcp_client, 0, &dns_server);
537 
538         /* Reset the buffer.  */
539         memset(buffer, 0, sizeof(buffer));
540 
541         /* Get DNS domain name.  */
542         nx_dhcpv6_get_other_option_data(&dhcp_client, NX_DHCPV6_DOMAIN_NAME_OPTION, buffer, 200);
543 
544         /* Reset the buffer.  */
545         memset(buffer, 0, sizeof(buffer));
546 
547         /* Get the time zone.  */
548         nx_dhcpv6_get_other_option_data(&dhcp_client, NX_DHCPV6_NEW_POSIX_TIMEZONE_OPTION, buffer, 200); // Try to get DNS info got from DHCPv6 Server
549 #endif
550 
551         /* At some point, we may wish to release the IPv6 address lease e.g. the device
552            is leaving the network or powering down. In that case we inform the
553            DHCPv6 Server that we are releasing the address lease. */
554         status = nx_dhcpv6_request_release(&dhcp_client);
555 
556         /* Check status.  */
557         if (status != NX_SUCCESS)
558         {
559 
560             error_counter++;
561             return;
562         }
563 
564         /* Send the release message.  */
565         tx_thread_sleep(NX_IP_PERIODIC_RATE);
566     }
567 
568     /* Stopping the Client task. */
569     status = nx_dhcpv6_stop(&dhcp_client);
570 
571     /* Check status.  */
572     if (status != NX_SUCCESS)
573     {
574 
575         error_counter++;
576         return;
577     }
578 
579     /* Clear the previously assigned IPv6 addresses from the Client and IP address table.  */
580     status = nx_dhcpv6_reinitialize(&dhcp_client);
581 
582     /* Check status.  */
583     if (status != NX_SUCCESS)
584     {
585 
586         error_counter++;
587         return;
588     }
589 
590     /* Start up the Client task again. */
591     status = nx_dhcpv6_start(&dhcp_client);
592 
593     /* Check status.  */
594     if (status != NX_SUCCESS)
595     {
596 
597         error_counter++;
598         return;
599     }
600 
601     /* Begin the request process by sending a Solicit message with the IA created above
602        with our preferred IPv6 address. */
603     status = nx_dhcpv6_request_solicit(&dhcp_client);
604     /* Check status.  */
605     if (status != NX_SUCCESS)
606     {
607 
608         error_counter++;
609         return;
610     }
611 
612     /* Wait a bit before releasing the IP address and terminating the client. */
613     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
614 
615     /* Ok, lets stop the application. Again we DO NOT plan
616        to keep the IPv6 address we were assigned and need to release it
617        back to the DHCPv6 server. */
618     status = nx_dhcpv6_request_release(&dhcp_client);
619 
620     /* Check for error. */
621     if (status != NX_SUCCESS)
622     {
623         error_counter++;
624     }
625 
626     /* Now delete the DHCPv6 client and release ThreadX and
627        NetX Duo resources back to the system. */
628     nx_dhcpv6_client_delete(&dhcp_client);
629 
630 
631     return;
632 
633 }
634 
635 
636 /* This is the notification from the DHCPv6 Client task that it has changed
637    state in the DHCPv6 protocol, for example getting assigned an IPv6 lease and
638    achieving the bound state or an IPv6 lease expires and being reset to
639    the init state.
640 */
dhcpv6_state_change_notify(NX_DHCPV6 * dhcpv6_ptr,UINT old_state,UINT new_state)641 VOID dhcpv6_state_change_notify(NX_DHCPV6 *dhcpv6_ptr, UINT old_state, UINT new_state)
642 {
643 
644     NX_PARAMETER_NOT_USED(dhcpv6_ptr);
645 
646     /* Increment state change counter. */
647     state_changes++;
648 
649     /* Check if the Client attempted to request an IPv6 lease but no servers
650        responded. */
651     if ((old_state == NX_DHCPV6_STATE_SENDING_SOLICIT) && (new_state == NX_DHCPV6_STATE_INIT))
652     {
653 
654         /* Indication that either DAD failed or IP lease expired. */
655         address_not_assigned++;
656     }
657 
658     /* Check if the Client has been assigned an IPv6 lease. */
659     if (new_state == NX_DHCPV6_STATE_BOUND_TO_ADDRESS)
660     {
661         bound_addresses++;
662     }
663 
664    /* Check if the Client was bound, but failed the uniqueness check
665        (Duplicate Address Detection) and was reset to the INIT state. */
666     if ((old_state == NX_DHCPV6_STATE_SENDING_DECLINE) && (new_state == NX_DHCPV6_STATE_INIT))
667     {
668 
669         /* Indication that DAD failed on Client IA. */
670         address_failed_dad++;
671     }
672 
673     /* Check if the Client was bound, attempted renew the lease but the
674        IPv6 address renewal/rebinding failed. */
675     if ((old_state == NX_DHCPV6_STATE_SENDING_REBIND) && (new_state == NX_DHCPV6_STATE_INIT))
676     {
677 
678         /* Indication that the IP lease expired. */
679         address_expired++;
680     }
681 
682 
683 
684     /* Other checks are possible. */
685 
686 }
687 
688 /* This is the notification from the DHCPv6 Client task that it received an error
689    from the server (status code) in response to the Client's last DHCPv6 message.
690 */
691 
dhcpv6_server_error_handler(NX_DHCPV6 * dhcpv6_ptr,UINT op_code,UINT status_code,UINT message_type)692 VOID dhcpv6_server_error_handler(NX_DHCPV6 *dhcpv6_ptr, UINT op_code, UINT status_code, UINT message_type)
693 {
694 
695     NX_PARAMETER_NOT_USED(dhcpv6_ptr);
696     NX_PARAMETER_NOT_USED(op_code);
697     NX_PARAMETER_NOT_USED(status_code);
698     NX_PARAMETER_NOT_USED(message_type);
699 
700     /* Increment the server error count. */
701     server_errors++;
702 
703     /* This should distinguish between receiving a server error and no server
704        available to assign the Client an IPv6 address if the Client fails
705        to get assigned an address. */
706 }
707 
708 #endif /* FEATURE_NX_IPV6 */
709