1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Component */
16 /** */
17 /** Dynamic Host Configuration Protocol over IPv6 (DHCPv6 Server) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_DHCPV6_SOURCE_CODE
23
24
25 /* Force error checking to be disabled in this module */
26
27 #ifndef NX_DISABLE_ERROR_CHECKING
28 #define NX_DISABLE_ERROR_CHECKING
29 #endif
30
31 /* Include necessary system files. */
32
33 #include <stdio.h>
34 #include "nx_api.h"
35 #include "nx_system.h"
36 #include "nx_ip.h"
37 #include "nx_ipv6.h"
38 #include "nx_udp.h"
39 #include "nxd_dhcpv6_server.h"
40 #include "tx_timer.h"
41
42 #ifdef FEATURE_NX_IPV6
43
44 /* Bring in externs for caller checking code. */
45
46 NX_CALLER_CHECKING_EXTERNS
47
48
49 /**************************************************************************/
50 /* */
51 /* FUNCTION RELEASE */
52 /* */
53 /* _nxe_dhcpv6_server_create PORTABLE C */
54 /* 6.1 */
55 /* AUTHOR */
56 /* */
57 /* Yuxin Zhou, Microsoft Corporation */
58 /* */
59 /* DESCRIPTION */
60 /* */
61 /* This function performs error checking on the NetX create dhcpv6 */
62 /* server service. */
63 /* */
64 /* INPUT */
65 /* */
66 /* dhcpv6_server_ptr Pointer to DHCPV6 server */
67 /* ip_ptr Pointer to server IP instance */
68 /* name_ptr DHCPV6 name pointer */
69 /* packet_pool_ptr Pointer to server packet pool */
70 /* stack_ptr Pointer to free memory */
71 /* stack_size Size of server stack memory */
72 /* dhcpv6_address_declined_handler Declined address request handler*/
73 /* dhcpv6_option_request_handler Option request handler */
74 /* */
75 /* OUTPUT */
76 /* */
77 /* status Completion status */
78 /* NX_PTR_ERROR Invalid pointer input */
79 /* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */
80 /* */
81 /* CALLS */
82 /* */
83 /* _nx_dhcpv6_server_create DHCPV6 server create service */
84 /* */
85 /* CALLED BY */
86 /* */
87 /* Application Code */
88 /* */
89 /* RELEASE HISTORY */
90 /* */
91 /* DATE NAME DESCRIPTION */
92 /* */
93 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
94 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
95 /* resulting in version 6.1 */
96 /* */
97 /**************************************************************************/
_nxe_dhcpv6_server_create(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_IP * ip_ptr,CHAR * name_ptr,NX_PACKET_POOL * packet_pool_ptr,VOID * stack_ptr,ULONG stack_size,VOID (* dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT * dhcpv6_server_ptr,NX_DHCPV6_CLIENT * dhcpv6_client_ptr,UINT message),VOID (* dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT * dhcpv6_server_ptr,UINT option_request,UCHAR * buffer_ptr,UINT * index))98 UINT _nxe_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr,
99 NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size,
100 VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message),
101 VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index))
102 {
103
104 UINT status;
105
106
107 /* Check for invalid pointer input. */
108 if (!dhcpv6_server_ptr ||!ip_ptr || !packet_pool_ptr || !stack_ptr)
109 {
110
111 return NX_PTR_ERROR;
112 }
113
114 /* Check for invalid non pointer input. */
115 if ((ip_ptr -> nx_ip_id != NX_IP_ID) || (stack_size < TX_MINIMUM_STACK))
116 {
117
118 return NX_DHCPV6_PARAM_ERROR;
119 }
120
121 /* Call actual DHCPV6 server create service. */
122 status = _nx_dhcpv6_server_create(dhcpv6_server_ptr, ip_ptr, name_ptr, packet_pool_ptr, stack_ptr, stack_size,
123 dhcpv6_address_declined_handler, dhcpv6_option_request_handler);
124
125 /* Return status. */
126 return(status);
127 }
128
129
130 /**************************************************************************/
131 /* */
132 /* FUNCTION RELEASE */
133 /* */
134 /* _nx_dhcpv6_server_create PORTABLE C */
135 /* 6.1 */
136 /* AUTHOR */
137 /* */
138 /* Yuxin Zhou, Microsoft Corporation */
139 /* */
140 /* DESCRIPTION */
141 /* */
142 /* This function creates the DHCPv6 Client instance with a Netx packet */
143 /* pool, processing thread, and various flag event queues, timers and */
144 /* mutexes necessary for DHCPv6 Client operations. */
145 /* */
146 /* Note: User is encouraged to call nx_dhcpv6_server_option_request */
147 /* _handler_set to set the option request handler. */
148 /* */
149 /* INPUT */
150 /* */
151 /* dhcpv6_server_ptr Pointer to DHCPV6 Server */
152 /* ip_ptr Pointer to Server IP instance */
153 /* name_ptr DHCPV6 name pointer */
154 /* packet_pool_ptr Pointer to Server packet pool */
155 /* stack_ptr Pointer to free memory */
156 /* stack_size Size of server stack memory */
157 /* dhcpv6_address_declined_handler Declined address request handler*/
158 /* dhcpv6_option_request_handler Option request handler */
159 /* */
160 /* OUTPUT */
161 /* */
162 /* status Actual completion status */
163 /* NX_SUCCESS Successful completion status */
164 /* */
165 /* CALLS */
166 /* */
167 /* tx_event_flags_create Create ThreadX flag event queue*/
168 /* tx_mutex_create Create mutex lock on resource */
169 /* nx_packet_pool_delete Delete the DHCPV6 packet pool */
170 /* nx_udp_socket_create Create the DHCPV6 UDP socket */
171 /* nx_udp_socket_delete Delete the DHCPV6 UDP socket */
172 /* tx_mutex_create Create DHCPV6 mutex */
173 /* tx_mutex_delete Delete DHCPV6 mutex */
174 /* tx_thread_create Create DHCPV6 processing thread*/
175 /* tx_thread_delete Delete DHCPV6 processing thread*/
176 /* tx_timer_create Create DHCPV6 timer */
177 /* tx_timer_delete Delete DHCPV6 timer */
178 /* */
179 /* CALLED BY */
180 /* */
181 /* Application Code */
182 /* */
183 /* RELEASE HISTORY */
184 /* */
185 /* DATE NAME DESCRIPTION */
186 /* */
187 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
188 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
189 /* resulting in version 6.1 */
190 /* */
191 /**************************************************************************/
_nx_dhcpv6_server_create(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_IP * ip_ptr,CHAR * name_ptr,NX_PACKET_POOL * packet_pool_ptr,VOID * stack_ptr,ULONG stack_size,VOID (* dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT * dhcpv6_server_ptr,NX_DHCPV6_CLIENT * dhcpv6_client_ptr,UINT message),VOID (* dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT * dhcpv6_server_ptr,UINT option_request,UCHAR * buffer_ptr,UINT * index))192 UINT _nx_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr,
193 NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size,
194 VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message),
195 VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index))
196 {
197
198 UINT i, status;
199 NX_DHCPV6_CLIENT *dhcpv6_client_ptr;
200
201
202 /* Initialize the DHCPV6 control block to zero. */
203 memset((void *) dhcpv6_server_ptr, 0, sizeof(NX_DHCPV6_SERVER));
204
205 /* Default the server global index to index 1. If otherwise, the host
206 application must set the DHCPv6 interface before it can start
207 the Server (nx_dhcpv6_server_interface_set). */
208 dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index = 1;
209
210 /* Link the DHCPv6 server with the IP instance. */
211 dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr = ip_ptr;
212
213 /* Set the DHCPV6 name. */
214 dhcpv6_server_ptr -> nx_dhcpv6_server_name = name_ptr;
215
216 /* Set the server packet pool. */
217 dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr = packet_pool_ptr;
218
219 /* Create the IP timer event flag instance. */
220 status = tx_event_flags_create(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events, "DHCPv6 Server Timer Events Queue");
221
222 /* Check for error. */
223 if (status != TX_SUCCESS)
224 {
225
226 return status;
227 }
228
229 /* Create the DHCPV6 mutex for the Server instance. */
230 status = tx_mutex_create(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex), "DHCPV6 Server Mutex", TX_NO_INHERIT);
231
232 /* Determine if the mutexes creation was successful. */
233 if (status)
234 {
235
236 /* Delete the flag queue. */
237 tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events);
238
239 /* No, return error status. */
240 return status;
241 }
242
243 /* Create the DHCPV6 processing thread. */
244 status = tx_thread_create(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread), "NetX DHCPV6 Server", _nx_dhcpv6_server_thread_entry,
245 (ULONG)(ALIGN_TYPE)dhcpv6_server_ptr, stack_ptr, stack_size,
246 NX_DHCPV6_SERVER_THREAD_PRIORITY, NX_DHCPV6_SERVER_THREAD_PRIORITY, 1, TX_DONT_START);
247
248 NX_THREAD_EXTENSION_PTR_SET(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread), dhcpv6_server_ptr)
249
250 /* Determine if the thread creation was successful. */
251 if (status)
252 {
253
254 /* Delete the server protection mutex. */
255 tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex));
256
257 /* Delete the flag queue. */
258 tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events);
259
260 /* No, return error status. */
261 return status;
262 }
263
264 /* Create the DHCPV6 timer for keeping track of IP lease time expiration. */
265 status = tx_timer_create(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer), "NetX DHCPV6 Server Lease timer",
266 _nx_dhcpv6_server_lease_timeout_entry, (ULONG)(ALIGN_TYPE)dhcpv6_server_ptr,
267 (NX_DHCPV6_IP_LEASE_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND) ,
268 (NX_DHCPV6_IP_LEASE_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND),
269 TX_NO_ACTIVATE);
270
271 NX_TIMER_EXTENSION_PTR_SET(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer), dhcpv6_server_ptr)
272
273 if (status != NX_SUCCESS)
274 {
275
276 /* Delete the DHCPv6 Server thread. */
277 tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread));
278
279 /* Delete the server protection mutex. */
280 tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex));
281
282 /* Delete the flag queue. */
283 tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events);
284 }
285
286 /* Create the DHCPV6 timer for keeping track of the DHCPv6 Client session time. */
287 status = tx_timer_create(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer), "NetX DHCPV6 Session Duration timer",
288 _nx_dhcpv6_server_session_timeout_entry, (ULONG)(ALIGN_TYPE)dhcpv6_server_ptr,
289 (NX_DHCPV6_SESSION_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND),
290 (NX_DHCPV6_SESSION_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND),
291 TX_NO_ACTIVATE);
292
293 NX_TIMER_EXTENSION_PTR_SET(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer), dhcpv6_server_ptr)
294
295 if (status != NX_SUCCESS)
296 {
297
298 /* Delete the server lease timer. */
299 tx_timer_delete( &(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer));
300
301 /* Delete the DHCPv6 Server thread. */
302 tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread));
303
304 /* Delete the server protection mutex. */
305 tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex));
306
307 /* Delete the flag queue. */
308 tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events);
309 }
310
311 /* Initialize the DHCPv6 client control blocks */
312 for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++)
313 {
314
315 /* Set a local pointer for convenience. */
316 dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i];
317
318 /* Clear the client record. */
319 memset(dhcpv6_client_ptr, 0, sizeof(NX_DHCPV6_CLIENT));
320 }
321
322 /* Determine if the timers creation were successful. */
323 if (status)
324 {
325
326 /* Delete the server lease timer. */
327 tx_timer_delete( &(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer));
328
329 /* Delete the server serssion timer. */
330 tx_timer_delete( &(dhcpv6_server_ptr -> nx_dhcpv6_session_timer));
331
332 /* Delete the DHCPv6 Server thread. */
333 tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread));
334
335 /* Delete the server protection mutex. */
336 tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex));
337
338 /* Delete the flag queue. */
339 tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events);
340
341 /* Return error status. */
342 return status;
343 }
344
345 /* Save the DHCPV6 instance pointer in the socket. */
346 dhcpv6_server_ptr -> nx_dhcpv6_server_socket.nx_udp_socket_reserved_ptr = (void *) dhcpv6_server_ptr;
347
348 /* Set the DHCPv6 Client ID. */
349 dhcpv6_server_ptr -> nx_dhcpv6_id = NX_DHCPV6_SERVER_ID;
350
351 /* Set the server preference for clients using multicast only for all request message types. */
352 dhcpv6_server_ptr -> nx_dhcpv6_server_multicast_only = NX_TRUE;
353
354 /* Assign the various handlers (server error messages, state change and expired/deprecated addresses). */
355 dhcpv6_server_ptr -> nx_dhcpv6_IP_address_declined_handler = dhcpv6_address_declined_handler;
356 dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler = dhcpv6_option_request_handler;
357
358 /* Return a successful status. */
359 return(NX_SUCCESS);
360 }
361
362
363 /**************************************************************************/
364 /* */
365 /* FUNCTION RELEASE */
366 /* */
367 /* _nxe_dhcpv6_server_option_request_handler_set PORTABLE C */
368 /* 6.1 */
369 /* AUTHOR */
370 /* */
371 /* Yuxin Zhou, Microsoft Corporation */
372 /* */
373 /* DESCRIPTION */
374 /* */
375 /* This function performs error checking on the NetX set dhcpv6 server */
376 /* option request callback service. */
377 /* */
378 /* INPUT */
379 /* */
380 /* dhcpv6_server_ptr Pointer to DHCPV6 server */
381 /* dhcpv6_option_request_handler_extended */
382 /* Extended option request handler */
383 /* */
384 /* OUTPUT */
385 /* */
386 /* status Completion status */
387 /* NX_PTR_ERROR Invalid pointer input */
388 /* */
389 /* CALLS */
390 /* */
391 /* _nx_dhcpv6_server_option_request_handler_set */
392 /* DHCPV6 server create service */
393 /* */
394 /* CALLED BY */
395 /* */
396 /* Application Code */
397 /* */
398 /* RELEASE HISTORY */
399 /* */
400 /* DATE NAME DESCRIPTION */
401 /* */
402 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
403 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
404 /* resulting in version 6.1 */
405 /* */
406 /**************************************************************************/
_nxe_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER * dhcpv6_server_ptr,VOID (* dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT * dhcpv6_server_ptr,UINT option_request,UCHAR * buffer_ptr,UINT * index,UINT available_payload))407 UINT _nxe_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr,
408 VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request,
409 UCHAR *buffer_ptr, UINT *index, UINT available_payload))
410 {
411
412 UINT status;
413
414
415 /* Check for invalid pointer input. */
416 if ((!dhcpv6_server_ptr) || (!dhcpv6_option_request_handler_extended))
417 {
418 return NX_PTR_ERROR;
419 }
420
421 /* Call actual DHCPV6 server option request handler set service. */
422 status = _nx_dhcpv6_server_option_request_handler_set(dhcpv6_server_ptr, dhcpv6_option_request_handler_extended);
423
424 /* Return status. */
425 return(status);
426 }
427
428
429 /**************************************************************************/
430 /* */
431 /* FUNCTION RELEASE */
432 /* */
433 /* _nx_dhcpv6_server_option_request_handler_set PORTABLE C */
434 /* 6.1 */
435 /* AUTHOR */
436 /* */
437 /* Yuxin Zhou, Microsoft Corporation */
438 /* */
439 /* DESCRIPTION */
440 /* */
441 /* This function sets the DHCPv6 option request handler. */
442 /* */
443 /* INPUT */
444 /* */
445 /* dhcpv6_server_ptr Pointer to DHCPV6 server */
446 /* dhcpv6_option_request_handler_extended */
447 /* Extended option request handler */
448 /* */
449 /* OUTPUT */
450 /* */
451 /* status Actual completion status */
452 /* NX_SUCCESS Successful completion status */
453 /* */
454 /* CALLS */
455 /* */
456 /* None */
457 /* */
458 /* CALLED BY */
459 /* */
460 /* Application Code */
461 /* */
462 /* RELEASE HISTORY */
463 /* */
464 /* DATE NAME DESCRIPTION */
465 /* */
466 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
467 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
468 /* resulting in version 6.1 */
469 /* */
470 /**************************************************************************/
_nx_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER * dhcpv6_server_ptr,VOID (* dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT * dhcpv6_server_ptr,UINT option_request,UCHAR * buffer_ptr,UINT * index,UINT available_payload))471 UINT _nx_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr,
472 VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request,
473 UCHAR *buffer_ptr, UINT *index, UINT available_payload))
474 {
475
476
477 /* Set the extended handler callback. */
478 dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler_extended = dhcpv6_option_request_handler_extended;
479
480 /* Return success. */
481 return(NX_SUCCESS);
482 }
483
484
485 /**************************************************************************/
486 /* */
487 /* FUNCTION RELEASE */
488 /* */
489 /* _nxe_dhcpv6_add_client_record PORTABLE C */
490 /* 6.1 */
491 /* AUTHOR */
492 /* */
493 /* Yuxin Zhou, Microsoft Corporation */
494 /* */
495 /* DESCRIPTION */
496 /* */
497 /* This function performs error checking for the copy client data */
498 /* service. */
499 /* */
500 /* INPUT */
501 /* */
502 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
503 /* table_index Table index to store client data */
504 /* message_xid Client transaction ID */
505 /* client_address IP address leased to client */
506 /* client_state Client DHCPv6 state e.g. bound */
507 /* IP_lease_time_accrued Time expired on current IP lease */
508 /* valid_lifetime When address becomes invalid */
509 /* duid_type Type of Client DUID */
510 /* duid_hardware DUID hardware (usually ethernet) */
511 /* physical_address_msw MSB of client mac address */
512 /* physical_address_lsw LSB of client mac address */
513 /* duid_time Time for link layer time DUID */
514 /* duid_vendor_number Enterprise ID for Vendor DUID */
515 /* duid_vendor_private Pointer to private ID for DUID */
516 /* duid_private_length Vendor Duid private ID length */
517 /* */
518 /* OUTPUT */
519 /* */
520 /* NX_SUCCESS Successful IP address copy */
521 /* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */
522 /* NX_DHCPV6_TABLE_FULL No empty slot for client data */
523 /* */
524 /* CALLS */
525 /* */
526 /* _nx_dhcpv6_add_client_record Actual copy client data service */
527 /* */
528 /* CALLED BY */
529 /* */
530 /* Application code */
531 /* */
532 /* RELEASE HISTORY */
533 /* */
534 /* DATE NAME DESCRIPTION */
535 /* */
536 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
537 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
538 /* resulting in version 6.1 */
539 /* */
540 /**************************************************************************/
_nxe_dhcpv6_add_client_record(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT table_index,ULONG message_xid,NXD_ADDRESS * client_address,UINT client_state,ULONG IP_lease_time_accrued,ULONG valid_lifetime,UINT duid_type,UINT duid_hardware,ULONG physical_address_msw,ULONG physical_address_lsw,ULONG duid_time,ULONG duid_vendor_number,UCHAR * duid_vendor_private,UINT duid_private_length)541 UINT _nxe_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state,
542 ULONG IP_lease_time_accrued, ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw,
543 ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length)
544 {
545
546 UINT status;
547
548 /* Check for invalid pointer input. */
549 if ((dhcpv6_server_ptr == NX_NULL) || (client_address == NX_NULL))
550 {
551
552 return NX_PTR_ERROR;
553 }
554
555 /* Check for missing transaction ID or DUID type. */
556 if ((message_xid == 0) || (duid_type == 0))
557 {
558 return NX_INVALID_PARAMETERS;
559 }
560
561 /* Check for missing time expired on the lease (if client in a bound state). */
562 if ((IP_lease_time_accrued == 0) && (client_state == NX_DHCPV6_STATE_BOUND))
563 {
564 return NX_INVALID_PARAMETERS;
565 }
566
567 /* Check for invalid enterprise DUID data if type is enterprise. */
568 if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED)
569 {
570
571 if ((duid_private_length == 0) || (duid_vendor_private == NX_NULL))
572 {
573
574 return NX_INVALID_PARAMETERS;
575 }
576 }
577 /* Check for invalid LINK LAYER duid data. */
578 else if ((duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) || (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY))
579 {
580
581 if ((physical_address_msw == 0) && (physical_address_lsw == 0))
582 {
583 return NX_INVALID_PARAMETERS;
584 }
585
586 if ((duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) && (duid_time == 0))
587 {
588 return NX_INVALID_PARAMETERS;
589 }
590 }
591
592 /* Call the actual service and return completion status. */
593 status = _nx_dhcpv6_add_client_record(dhcpv6_server_ptr, table_index, message_xid, client_address, client_state,
594 IP_lease_time_accrued, valid_lifetime, duid_type, duid_hardware, physical_address_msw, physical_address_lsw,
595 duid_time, duid_vendor_number, duid_vendor_private, duid_private_length);
596 return status;
597 }
598
599
600 /**************************************************************************/
601 /* */
602 /* FUNCTION RELEASE */
603 /* */
604 /* _nx_dhcpv6_add_client_record PORTABLE C */
605 /* 6.1 */
606 /* AUTHOR */
607 /* */
608 /* Yuxin Zhou, Microsoft Corporation */
609 /* */
610 /* DESCRIPTION */
611 /* */
612 /* This function copies the input data into a DHCPv6 Client record and */
613 /* stored in the server's Client table. It then uses the Client IP */
614 /* address to find the matching record in the server IP lease table to */
615 /* cross link the tables. */
616 /* */
617 /* This is intended to satisfy the DHCPv6 protocol requirement that a */
618 /* DHPCv6 Server be able to store and retrieve lease data from */
619 /* nonvolatile memory e..g between reboots. */
620 /* */
621 /* INPUT */
622 /* */
623 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
624 /* table_index Table index to store client data */
625 /* message_xid Client transaction ID */
626 /* client_address IP address leased to client */
627 /* client_state Client DHCPv6 state e.g. bound */
628 /* IP_lease_time_accrued Time expired on current IP lease */
629 /* valid_lifetime When address becomes invalid */
630 /* duid_type Type of Client DUID */
631 /* duid_hardware DUID hardware (usually ethernet) */
632 /* physical_address_msw MSB of client mac address */
633 /* physical_address_lsw LSB of client mac address */
634 /* duid_time Time for link layer time DUID */
635 /* duid_vendor_number Enterprise ID for Vendor DUID */
636 /* duid_vendor_private Pointer to private ID for DUID */
637 /* duid_private_length Vendor Duid private ID length */
638 /* */
639 /* OUTPUT */
640 /* */
641 /* NX_SUCCESS Successful IP address copy */
642 /* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */
643 /* NX_DHCPV6_TABLE_FULL No empty slot for client data */
644 /* */
645 /* CALLS */
646 /* */
647 /* memcpy Copy data to specified memory */
648 /* */
649 /* CALLED BY */
650 /* */
651 /* Application code */
652 /* */
653 /* RELEASE HISTORY */
654 /* */
655 /* DATE NAME DESCRIPTION */
656 /* */
657 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
658 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
659 /* verified memcpy use cases, */
660 /* resulting in version 6.1 */
661 /* */
662 /**************************************************************************/
_nx_dhcpv6_add_client_record(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT table_index,ULONG message_xid,NXD_ADDRESS * client_address,UINT client_state,ULONG IP_lease_time_accrued,ULONG valid_lifetime,UINT duid_type,UINT duid_hardware,ULONG physical_address_msw,ULONG physical_address_lsw,ULONG duid_time,ULONG duid_vendor_number,UCHAR * duid_vendor_private,UINT duid_private_length)663 UINT _nx_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state,
664 ULONG IP_lease_time_accrued, ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw,
665 ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length)
666 {
667
668 UINT i;
669 UINT found = NX_FALSE;
670 NX_DHCPV6_CLIENT *dhcpv6_client_ptr;
671
672
673 /* Check if a table index was specified. */
674 if (table_index != 0xFFFFFFFF)
675 {
676
677 /* Check if it is a valid index. */
678 if (table_index >= NX_DHCPV6_MAX_CLIENTS)
679 {
680
681 /* No, return a parameter error. */
682 return NX_INVALID_PARAMETERS;
683 }
684
685 /* Check if it is actually empty. */
686 if (dhcpv6_server_ptr -> nx_dhcpv6_clients[table_index].nx_dhcpv6_message_xid != 0)
687 {
688
689 /* Not empty. Indicate we'll have to find an empty slot. */
690 table_index = 0xFFFFFFFF;
691 }
692 }
693
694 /* Check if we still need to find a slot. */
695 if (table_index == 0xFFFFFFFF)
696 {
697
698 /* We do, so loop through client records to find one. */
699 for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++)
700 {
701
702 /* Is this an empty slot? */
703 if (dhcpv6_server_ptr -> nx_dhcpv6_clients[i].nx_dhcpv6_message_xid == 0)
704 {
705
706 /* This is available. */
707 table_index = i;
708 break;
709 }
710 }
711
712 /* Do we have a slot? */
713 if (i == NX_DHCPV6_MAX_CLIENTS)
714 {
715
716 /* No, Indicate the table is full. */
717 return NX_DHCPV6_TABLE_FULL;
718 }
719 }
720
721 /* Create the table entry. */
722
723 /* Fill in the generic client information. */
724 dhcpv6_client_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_clients[table_index]);
725 dhcpv6_client_ptr -> nx_dhcpv6_id = NX_DHCPV6_CLIENT_ID;
726 dhcpv6_client_ptr -> nx_dhcpv6_message_xid = message_xid;
727 dhcpv6_client_ptr -> nx_dhcpv6_state = (UCHAR)client_state;
728 dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued = IP_lease_time_accrued;
729 memcpy(&(dhcpv6_client_ptr -> nx_dhcpv6_server_duid), &(dhcpv6_server_ptr -> nx_dhcpv6_server_duid), sizeof(NX_DHCPV6_SVR_DUID)); /* Use case of memcpy is verified. */
730
731 /*Fill in the Client DUID information. */
732 dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_op_code = NX_DHCPV6_OP_DUID_CLIENT;
733 dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type = (USHORT)duid_hardware;
734 dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_type = (USHORT)duid_type;
735
736 /* Determine DUID type to fill in the rest of the DUID fields. */
737 if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED)
738 {
739
740 /* Validate the DUID private length. */
741 if (duid_private_length > NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH)
742 {
743 return NX_DHCPV6_INVALID_DUID;
744 }
745
746 dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_enterprise_number = duid_vendor_number;
747 memcpy(&(dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_private_identifier[0]), duid_vendor_private, duid_private_length); /* Use case of memcpy is verified. */
748 dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_option_length = (USHORT)(duid_private_length + 6);
749 }
750 else
751 {
752
753 /* Either link layer or link layer plus time. */
754 dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw = (USHORT)physical_address_msw;
755 dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw = physical_address_lsw;
756 dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_option_length = 10;
757
758 if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME)
759 {
760
761 dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_option_length = 14;
762 dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_time = duid_time;
763 }
764 }
765
766 /* Fill in the necessary IA-NA and IA Address option fields. */
767 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code = NX_DHCPV6_OP_IA_ADDRESS;
768 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length = 24;
769 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = valid_lifetime;
770 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; /* Don't care */
771 COPY_NXD_ADDRESS(client_address, &(dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address));
772
773 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_op_code = NX_DHCPV6_OP_OPTION_STATUS;
774 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_option_length = 2; /* No message */
775 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_SUCCESS;
776
777 /* Now access the server lease table to find this client's lease. */
778 for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++)
779 {
780
781 /* Compare our client's assigned IP address with this lease table entry. */
782 if(CHECK_IPV6_ADDRESSES_SAME(&(client_address -> nxd_ip_address.v6[0]),
783 &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0])))
784 {
785
786 /* They match! Cross link the tables. */
787 dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = dhcpv6_client_ptr;
788 found = NX_TRUE;
789 break;
790 }
791 }
792
793 if (!found)
794 {
795
796 /* This client apparently does not have a valid IP lease. Ok to keep in the tables,
797 but they will need to request an IP address! */
798 return NX_DHCPV6_ADDRESS_NOT_FOUND;
799 }
800
801 return NX_SUCCESS;
802
803 }
804
805
806 /**************************************************************************/
807 /* */
808 /* FUNCTION RELEASE */
809 /* */
810 /* _nxe_dhcpv6_retrieve_client_record PORTABLE C */
811 /* 6.1 */
812 /* AUTHOR */
813 /* */
814 /* Yuxin Zhou, Microsoft Corporation */
815 /* */
816 /* DESCRIPTION */
817 /* */
818 /* This function performs error checking on the retrieve DHCPv6 Client */
819 /* record service. */
820 /* */
821 /* INPUT */
822 /* */
823 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
824 /* table_index Table index to store client data */
825 /* message_xid Client transaction ID */
826 /* client_address IP address leased to client */
827 /* client_state Client DHCPv6 state e.g. bound */
828 /* IP_lease_time_accrued Time expired on current IP lease */
829 /* valid_lifetime When address becomes invalid */
830 /* duid_type Type of Client DUID */
831 /* duid_hardware DUID hardware (usually ethernet) */
832 /* physical_address_msw MSB of client mac address */
833 /* physical_address_lsw LSB of client mac address */
834 /* duid_time Time for link layer time DUID */
835 /* duid_vendor_number Enterprise ID for Vendor DUID */
836 /* duid_vendor_private Pointer to private ID for DUID */
837 /* duid_private_length Vendor Duid private ID length */
838 /* */
839 /* OUTPUT */
840 /* */
841 /* NX_SUCCESS Successful IP address copy */
842 /* NX_INVALID_PARAMETERS Invalid non pointer input */
843 /* */
844 /* CALLS */
845 /* */
846 /* _nx_dhcpv6_retrieve_client_record Actual retrieve client data */
847 /* service */
848 /* */
849 /* CALLED BY */
850 /* */
851 /* Application code */
852 /* */
853 /* RELEASE HISTORY */
854 /* */
855 /* DATE NAME DESCRIPTION */
856 /* */
857 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
858 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
859 /* resulting in version 6.1 */
860 /* */
861 /**************************************************************************/
_nxe_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT table_index,ULONG * message_xid,NXD_ADDRESS * client_address,UINT * client_state,ULONG * IP_lease_time_accrued,ULONG * valid_lifetime,UINT * duid_type,UINT * duid_hardware,ULONG * physical_address_msw,ULONG * physical_address_lsw,ULONG * duid_time,ULONG * duid_vendor_number,UCHAR * duid_vendor_private,UINT * duid_private_length)862 UINT _nxe_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state,
863 ULONG *IP_lease_time_accrued, ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw,
864 ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length)
865 {
866
867 UINT status;
868
869
870 /* Check for invalid parameters. */
871 if (table_index >= NX_DHCPV6_MAX_CLIENTS)
872 {
873 return NX_INVALID_PARAMETERS;
874 }
875
876 /* Check for invalid pointer input. */
877 if ((dhcpv6_server_ptr == NX_NULL) || (message_xid == NX_NULL) || (client_address == NX_NULL) || (client_state == NX_NULL) ||
878 (IP_lease_time_accrued == NX_NULL) || (valid_lifetime == NX_NULL) || (duid_type == NX_NULL))
879 {
880
881 return NX_PTR_ERROR;
882 }
883
884
885 /* Call the actual service. */
886 status = _nx_dhcpv6_retrieve_client_record(dhcpv6_server_ptr, table_index, message_xid, client_address, client_state,
887 IP_lease_time_accrued, valid_lifetime, duid_type, duid_hardware, physical_address_msw,
888 physical_address_lsw, duid_time, duid_vendor_number, duid_vendor_private, duid_private_length);
889
890 return status;
891 }
892
893
894 /**************************************************************************/
895 /* */
896 /* FUNCTION RELEASE */
897 /* */
898 /* _nx_dhcpv6_retrieve_client_record PORTABLE C */
899 /* 6.1 */
900 /* AUTHOR */
901 /* */
902 /* Yuxin Zhou, Microsoft Corporation */
903 /* */
904 /* DESCRIPTION */
905 /* */
906 /* This function returns DHCPv6 Client record data at the specified */
907 /* index into the server table to the caller. Note that if a slot in */
908 /* the server's client table is empty, evidenced by a zero transaction */
909 /* ID, the service returns null data in all parameters with a successful*/
910 /* completion status. */
911 /* */
912 /* This is intended to satisfy the DHCPv6 protocol requirement that a */
913 /* DHPCv6 Server be able to store and retrieve IP lease data from */
914 /* nonvolatile memory e..g between reboots. */
915 /* */
916 /* INPUT */
917 /* */
918 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
919 /* table_index Table index to store client data */
920 /* message_xid Client transaction ID */
921 /* client_address IP address leased to client */
922 /* client_state Client DHCPv6 state e.g. bound */
923 /* IP_lease_time_accrued Time expired on current IP lease */
924 /* valid_lifetime When address becomes invalid */
925 /* duid_type Type of Client DUID */
926 /* duid_hardware DUID hardware (usually ethernet) */
927 /* physical_address_msw MSB of client mac address */
928 /* physical_address_lsw LSB of client mac address */
929 /* duid_time Time for link layer time DUID */
930 /* duid_vendor_number Enterprise ID for Vendor DUID */
931 /* duid_vendor_private Pointer to private ID for DUID */
932 /* duid_private_length Vendor Duid private ID length */
933 /* */
934 /* OUTPUT */
935 /* */
936 /* NX_SUCCESS Successful IP address copy */
937 /* NX_PTR_ERROR Invalid pointer input */
938 /* NX_INVALID_PARAMETERS Invalid non pointer input */
939 /* NX_DHCPV6_INVALID_DUID Malformed DUID retrieved */
940 /* */
941 /* CALLS */
942 /* */
943 /* COPY_NXD_ADDRESS Copy IPv6 address to specified */
944 /* memory (holding an IPv6 address*/
945 /* */
946 /* CALLED BY */
947 /* */
948 /* Application code */
949 /* */
950 /* RELEASE HISTORY */
951 /* */
952 /* DATE NAME DESCRIPTION */
953 /* */
954 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
955 /* 09-30-2020 Yuxin Zhou Modified comment(s), corrected*/
956 /* the length of identifier, */
957 /* resulting in version 6.1 */
958 /* */
959 /**************************************************************************/
_nx_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT table_index,ULONG * message_xid,NXD_ADDRESS * client_address,UINT * client_state,ULONG * IP_lease_time_accrued,ULONG * valid_lifetime,UINT * duid_type,UINT * duid_hardware,ULONG * physical_address_msw,ULONG * physical_address_lsw,ULONG * duid_time,ULONG * duid_vendor_number,UCHAR * duid_vendor_private,UINT * duid_private_length)960 UINT _nx_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state,
961 ULONG *IP_lease_time_accrued, ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw,
962 ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length)
963 {
964
965 NX_DHCPV6_CLIENT *client_ptr;
966 INT length;
967
968
969 /* Get a local pointer for convenience. */
970 client_ptr = &(dhcpv6_server_ptr ->nx_dhcpv6_clients[table_index]);
971
972 /* Load the generic client data. */
973 *message_xid = client_ptr -> nx_dhcpv6_message_xid;
974
975 /* Is this an empty record? */
976 if (*message_xid == 0)
977 {
978
979 /* Yes so return null data. */
980 memset(client_address, 0, sizeof(NXD_ADDRESS));
981 *client_state = 0;
982 *IP_lease_time_accrued = 0;
983 *valid_lifetime = 0;
984 *duid_type = 0;
985 if (duid_hardware)
986 *duid_hardware = 0;
987 if (physical_address_msw)
988 *physical_address_msw = 0;
989 if (physical_address_lsw)
990 *physical_address_lsw = 0;
991 if (duid_time)
992 *duid_time = 0;
993 if (duid_vendor_number)
994 *duid_vendor_number = 0;
995 if (duid_private_length)
996 *duid_private_length = 0;
997
998 return NX_SUCCESS;
999 }
1000
1001 /* Not an empty record. Extract the data! */
1002 COPY_NXD_ADDRESS(&(client_ptr -> nx_dhcpv6_ia.nx_global_address), client_address);
1003 *client_state = client_ptr -> nx_dhcpv6_state;
1004 *IP_lease_time_accrued = client_ptr -> nx_dhcpv6_IP_lease_time_accrued;
1005 *valid_lifetime = client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime;
1006 *duid_type = client_ptr -> nx_dhcpv6_client_duid.nx_duid_type;
1007
1008 /* If this is a LINK LAYER Duid type, load the appropriate data. */
1009 if ((*duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY) || (*duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME))
1010 {
1011
1012 /* Check for invalid pointer input for DUID of the link layer type. */
1013 if ((duid_hardware == NX_NULL) || (physical_address_msw == NX_NULL) || (physical_address_lsw == NX_NULL))
1014 {
1015 return NX_PTR_ERROR;
1016 }
1017
1018 *duid_hardware = client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type;
1019 *physical_address_msw = client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw;
1020 *physical_address_lsw = client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw;
1021
1022 if (*duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME)
1023 {
1024
1025 if (duid_time == NX_NULL)
1026 {
1027 return NX_PTR_ERROR;
1028 }
1029
1030 *duid_time = client_ptr -> nx_dhcpv6_client_duid.nx_duid_time;
1031 }
1032 }
1033 else
1034 {
1035
1036 /* Client DUID type is vendor assigned. */
1037
1038 /* Check for valid pointer input for enterprise ID data */
1039 if ((duid_vendor_number == NX_NULL) || (duid_vendor_private == NX_NULL) || (duid_private_length == NX_NULL))
1040 {
1041 return NX_PTR_ERROR;
1042 }
1043
1044 *duid_vendor_number = client_ptr -> nx_dhcpv6_client_duid.nx_duid_enterprise_number;
1045 length = client_ptr -> nx_dhcpv6_client_duid.nx_option_length - 6;
1046 if (length < 0)
1047 {
1048 return NX_DHCPV6_INVALID_DUID;
1049 }
1050
1051 /* NOTE: The duid_vendor_private buffer is provided by user, and the buffer size must be not less than NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH. */
1052 memcpy(duid_vendor_private, &(client_ptr -> nx_dhcpv6_client_duid.nx_duid_private_identifier[0]), (UINT)length); /* Use case of memcpy is verified. The buffer is provided by user. */
1053 *duid_private_length = (UINT)length;
1054 }
1055
1056 return NX_SUCCESS;
1057 }
1058
1059
1060 /**************************************************************************/
1061 /* */
1062 /* FUNCTION RELEASE */
1063 /* */
1064 /* _nxe_dhcpv6_add_ip_address_lease PORTABLE C */
1065 /* 6.1 */
1066 /* AUTHOR */
1067 /* */
1068 /* Yuxin Zhou, Microsoft Corporation */
1069 /* */
1070 /* DESCRIPTION */
1071 /* */
1072 /* This function performs error checking for the copy lease service. */
1073 /* */
1074 /* INPUT */
1075 /* */
1076 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
1077 /* table_index Table index to store data */
1078 /* lease_IP_address Lease IP address */
1079 /* T1 T1 lifetime (when to renew) */
1080 /* T2 T2 lifetime (when to rebind) */
1081 /* preferred_lifetime When address becomes deprecated */
1082 /* valid_lifetime When address becomes invalid */
1083 /* */
1084 /* OUTPUT */
1085 /* */
1086 /* NX_SUCCESS Successful IP address copy */
1087 /* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */
1088 /* NX_PTR_ERROR Invalid pointer input */
1089 /* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */
1090 /* Address not onlink with Server */
1091 /* DHCPv6 network interface */
1092 /* CALLS */
1093 /* */
1094 /* _nx_dhcpv6_add_ip_address_lease Actual copy lease data service */
1095 /* */
1096 /* CALLED BY */
1097 /* */
1098 /* Application code */
1099 /* */
1100 /* RELEASE HISTORY */
1101 /* */
1102 /* DATE NAME DESCRIPTION */
1103 /* */
1104 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1105 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1106 /* resulting in version 6.1 */
1107 /* */
1108 /**************************************************************************/
_nxe_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT table_index,NXD_ADDRESS * lease_IP_address,ULONG T1,ULONG T2,ULONG valid_lifetime,ULONG preferred_lifetime)1109 UINT _nxe_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address,
1110 ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetime)
1111 {
1112
1113 UINT status;
1114
1115
1116 /* Check for invalid pointer input. */
1117 if ((dhcpv6_server_ptr == NX_NULL) || (lease_IP_address == NX_NULL))
1118 {
1119
1120 return NX_PTR_ERROR;
1121 }
1122
1123 /* Check for invalid non pointer input. */
1124 if (CHECK_UNSPECIFIED_ADDRESS(&(lease_IP_address -> nxd_ip_address.v6[0])))
1125 {
1126
1127 return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS;
1128 }
1129
1130 /* Check for invalid lease time data. */
1131 if ((T1 == 0) || (T2 == 0) || (valid_lifetime == 0) || (preferred_lifetime == 0))
1132 {
1133
1134 return NX_DHCPV6_PARAM_ERROR;
1135 }
1136
1137 /* Call the actual service and return completion status. */
1138 status = _nx_dhcpv6_add_ip_address_lease(dhcpv6_server_ptr, table_index, lease_IP_address,
1139 T1, T2, valid_lifetime, preferred_lifetime);
1140
1141 return status;
1142 }
1143
1144
1145 /**************************************************************************/
1146 /* */
1147 /* FUNCTION RELEASE */
1148 /* */
1149 /* _nx_dhcpv6_add_ip_address_lease PORTABLE C */
1150 /* 6.1 */
1151 /* AUTHOR */
1152 /* */
1153 /* Yuxin Zhou, Microsoft Corporation */
1154 /* */
1155 /* DESCRIPTION */
1156 /* */
1157 /* This function copies lease data into the Server IP lease table. */
1158 /* The caller can specify which slot with a index value up to the size */
1159 /* of the lease table, (NX_DHCPV6_MAX_LEASES - 1), or the DHCPv6 server */
1160 /* will find an empty slot to store the lease data if the table index is*/
1161 /* set to 'infinity' e.g. 0xFFFFFFFF. */
1162 /* */
1163 /* This is intended to satisfy the DHCPv6 protocol requirement that a */
1164 /* DHPCv6 Server be able to store and retrieve IP lease data from */
1165 /* nonvolatile memory e..g between reboots. */
1166 /* */
1167 /* INPUT */
1168 /* */
1169 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
1170 /* table_index Table index to store data */
1171 /* lease_IP_address Lease IP address */
1172 /* T1 T1 lifetime (when to renew) */
1173 /* T2 T2 lifetime (when to rebind) */
1174 /* preferred_lifetime When address becomes deprecated */
1175 /* valid_lifetime When address becomes invalid */
1176 /* */
1177 /* OUTPUT */
1178 /* */
1179 /* NX_SUCCESS Successful IP address copy */
1180 /* NX_DHCPV6_PARAM_ERROR Invalid table index */
1181 /* NX_DHCPV6_TABLE_FULL No empty entries for lease data */
1182 /* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */
1183 /* Address not onlink with Server */
1184 /* DHCPv6 network interface */
1185 /* CALLS */
1186 /* */
1187 /* None */
1188 /* */
1189 /* CALLED BY */
1190 /* */
1191 /* Application code */
1192 /* */
1193 /* RELEASE HISTORY */
1194 /* */
1195 /* DATE NAME DESCRIPTION */
1196 /* */
1197 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1198 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1199 /* resulting in version 6.1 */
1200 /* */
1201 /**************************************************************************/
_nx_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT table_index,NXD_ADDRESS * lease_IP_address,ULONG T1,ULONG T2,ULONG valid_lifetime,ULONG preferred_lifetime)1202 UINT _nx_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address,
1203 ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetime)
1204 {
1205
1206 UINT i;
1207 NX_DHCPV6_ADDRESS_LEASE *lease_ptr;
1208 UINT ga_address_index;
1209 UINT prefix_length;
1210
1211
1212 /* Get the DHCPv6 server address interface index. */
1213 ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index;
1214
1215 prefix_length = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length;
1216
1217 /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the
1218 network masked addresses should be equal). */
1219
1220 if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]),
1221 &lease_IP_address -> nxd_ip_address.v6[0], prefix_length))
1222 {
1223
1224 return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS;
1225 }
1226
1227 /* Is there a table index specified? */
1228 if (table_index == 0xFFFFFFFF)
1229 {
1230
1231 /* No, so lets search the server table and find an available slot. */
1232 for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++)
1233 {
1234
1235 /* Get a local pointer for convenience. */
1236 lease_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]);
1237
1238 /* Does this slot have an address already? */
1239 if (CHECK_UNSPECIFIED_ADDRESS(&(lease_ptr -> nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0])))
1240 {
1241
1242 /* This one looks empty. */
1243 table_index = i;
1244 break;
1245 }
1246 }
1247
1248 if (table_index == 0xFFFFFFFF)
1249 {
1250 return NX_DHCPV6_TABLE_FULL;
1251 }
1252 }
1253 else
1254 {
1255 /* Check for valid table index. */
1256 if (table_index >= NX_DHCPV6_MAX_LEASES)
1257 {
1258
1259 /* No good. Exceeds the size of the table. */
1260 return NX_DHCPV6_PARAM_ERROR;
1261 }
1262 }
1263
1264 /* Copy the supplied IP data into the lease entry. */
1265 lease_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[table_index]);
1266
1267 COPY_NXD_ADDRESS(lease_IP_address, &(lease_ptr -> nx_dhcpv6_lease_IP_address));
1268 lease_ptr -> nx_dhcpv6_lease_T1_lifetime = T1;
1269 lease_ptr -> nx_dhcpv6_lease_T2_lifetime = T2;
1270 lease_ptr -> nx_dhcpv6_lease_valid_lifetime = valid_lifetime;
1271 lease_ptr -> nx_dhcpv6_lease_preferred_lifetime =preferred_lifetime;
1272
1273 dhcpv6_server_ptr -> nx_dhcpv6_assignable_addresses++;
1274
1275 return NX_SUCCESS;
1276 }
1277
1278
1279 /**************************************************************************/
1280 /* */
1281 /* FUNCTION RELEASE */
1282 /* */
1283 /* _nxe_dhcpv6_retrieve_ip_address_lease PORTABLE C */
1284 /* 6.1 */
1285 /* AUTHOR */
1286 /* */
1287 /* Yuxin Zhou, Microsoft Corporation */
1288 /* */
1289 /* DESCRIPTION */
1290 /* */
1291 /* This function performs error checking for the actual retrieve lease */
1292 /* service. */
1293 /* */
1294 /* This is intended to satisfy the DHCPv6 protocol requirement that a */
1295 /* DHPCv6 Server be able to store and retrieve lease data from */
1296 /* nonvolatile memory e..g between reboots. */
1297 /* */
1298 /* INPUT */
1299 /* */
1300 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
1301 /* table_index Table index to obtain data */
1302 /* lease_IP_address Lease IP address */
1303 /* T1 T1 lifetime (when to renew) */
1304 /* T2 T2 lifetime (when to rebind) */
1305 /* preferred_lifetime When address becomes deprecated */
1306 /* valid_lifetime When address becomes invalid */
1307 /* */
1308 /* OUTPUT */
1309 /* */
1310 /* NX_SUCCESS Successful IP address copy */
1311 /* NX_PTR_ERROR Invalid pointer input */
1312 /* */
1313 /* CALLS */
1314 /* */
1315 /* _nx_dhcpv6_retrieve_ip_address_lease */
1316 /* Actual retrieve data service */
1317 /* */
1318 /* CALLED BY */
1319 /* */
1320 /* Application code */
1321 /* */
1322 /* RELEASE HISTORY */
1323 /* */
1324 /* DATE NAME DESCRIPTION */
1325 /* */
1326 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1327 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1328 /* resulting in version 6.1 */
1329 /* */
1330 /**************************************************************************/
_nxe_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT table_index,NXD_ADDRESS * lease_IP_address,ULONG * T1,ULONG * T2,ULONG * valid_lifetime,ULONG * preferred_lifetime)1331 UINT _nxe_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address,
1332 ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime)
1333 {
1334
1335 UINT status;
1336
1337
1338 /* Check for invalid pointer input. */
1339 if ((dhcpv6_server_ptr == NX_NULL) || (lease_IP_address == NX_NULL) || (T1 == NX_NULL) ||
1340 (T2 == NX_NULL) || (valid_lifetime == NX_NULL) || (preferred_lifetime == NX_NULL))
1341 {
1342
1343 return NX_PTR_ERROR;
1344 }
1345
1346 status = _nx_dhcpv6_retrieve_ip_address_lease(dhcpv6_server_ptr, table_index, lease_IP_address,
1347 T1, T2, valid_lifetime, preferred_lifetime);
1348
1349 return status;
1350 }
1351
1352
1353 /**************************************************************************/
1354 /* */
1355 /* FUNCTION RELEASE */
1356 /* */
1357 /* _nx_dhcpv6_retrieve_ip_address_lease PORTABLE C */
1358 /* 6.1 */
1359 /* AUTHOR */
1360 /* */
1361 /* Yuxin Zhou, Microsoft Corporation */
1362 /* */
1363 /* DESCRIPTION */
1364 /* */
1365 /* This function retrieves lease data from the Server IP lease table. */
1366 /* The caller must specify which slot with a index value up to the size */
1367 /* of the lease table, (NX_DHCPV6_MAX_LEASES - 1). */
1368 /* */
1369 /* This is intended to satisfy the DHCPv6 protocol requirement that a */
1370 /* DHPCv6 Server be able to store and retrieve lease data from */
1371 /* nonvolatile memory e..g between reboots. */
1372 /* */
1373 /* INPUT */
1374 /* */
1375 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
1376 /* table_index Table index to obtain data */
1377 /* lease_IP_address Lease IP address */
1378 /* T1 T1 lifetime (when to renew) */
1379 /* T2 T2 lifetime (when to rebind) */
1380 /* preferred_lifetime When address becomes deprecated */
1381 /* valid_lifetime When address becomes invalid */
1382 /* */
1383 /* OUTPUT */
1384 /* */
1385 /* NX_SUCCESS Successful IP address copy */
1386 /* NX_DHCPV6_PARAM_ERROR Invalid table index */
1387 /* */
1388 /* CALLS */
1389 /* */
1390 /* None */
1391 /* */
1392 /* CALLED BY */
1393 /* */
1394 /* Application code */
1395 /* */
1396 /* RELEASE HISTORY */
1397 /* */
1398 /* DATE NAME DESCRIPTION */
1399 /* */
1400 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1401 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1402 /* resulting in version 6.1 */
1403 /* */
1404 /**************************************************************************/
_nx_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT table_index,NXD_ADDRESS * lease_IP_address,ULONG * T1,ULONG * T2,ULONG * valid_lifetime,ULONG * preferred_lifetime)1405 UINT _nx_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address,
1406 ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime)
1407 {
1408
1409 NX_DHCPV6_ADDRESS_LEASE *lease_ptr;
1410
1411
1412 /* Check for valid table index. */
1413 if (table_index >= NX_DHCPV6_MAX_LEASES)
1414 {
1415
1416 /* No good. Exceeds the size of the table. */
1417 return NX_DHCPV6_PARAM_ERROR;
1418 }
1419
1420 /* Get a local pointer for convenience. */
1421 lease_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[table_index]);
1422
1423 /* Copy the lease data into the input pointer buffers. */
1424 COPY_NXD_ADDRESS(&(lease_ptr -> nx_dhcpv6_lease_IP_address), lease_IP_address);
1425 *T1 = lease_ptr -> nx_dhcpv6_lease_T1_lifetime;
1426 *T2 = lease_ptr -> nx_dhcpv6_lease_T2_lifetime;
1427 *valid_lifetime = lease_ptr -> nx_dhcpv6_lease_valid_lifetime;
1428 *preferred_lifetime = lease_ptr -> nx_dhcpv6_lease_preferred_lifetime;
1429
1430 return NX_SUCCESS;
1431 }
1432
1433
1434 /**************************************************************************/
1435 /* */
1436 /* FUNCTION RELEASE */
1437 /* */
1438 /* _nxe_dhcpv6_server_delete PORTABLE C */
1439 /* 6.1 */
1440 /* AUTHOR */
1441 /* */
1442 /* Yuxin Zhou, Microsoft Corporation */
1443 /* */
1444 /* DESCRIPTION */
1445 /* */
1446 /* This function performs error checking on the NetX delete dhcpv6 */
1447 /* server service. */
1448 /* */
1449 /* INPUT */
1450 /* */
1451 /* dhcpv6_server_ptr Pointer to DHCPV6 server */
1452 /* */
1453 /* OUTPUT */
1454 /* */
1455 /* OUTPUT */
1456 /* */
1457 /* status Completion status */
1458 /* NX_PTR_ERROR Invalid pointer input */
1459 /* */
1460 /* */
1461 /* CALLS */
1462 /* */
1463 /* _nx_dhcpv6_server_delete Actual DHCPV6 delete function */
1464 /* */
1465 /* CALLED BY */
1466 /* */
1467 /* Application Code */
1468 /* */
1469 /* RELEASE HISTORY */
1470 /* */
1471 /* DATE NAME DESCRIPTION */
1472 /* */
1473 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1474 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1475 /* resulting in version 6.1 */
1476 /* */
1477 /**************************************************************************/
_nxe_dhcpv6_server_delete(NX_DHCPV6_SERVER * dhcpv6_server_ptr)1478 UINT _nxe_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
1479 {
1480
1481 UINT status;
1482
1483
1484 /* Check for invalid input pointers. */
1485 if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID))
1486 return(NX_PTR_ERROR);
1487
1488 /* Check for appropriate caller. */
1489 NX_THREADS_ONLY_CALLER_CHECKING
1490
1491 /* Call actual DHCPV6 server delete service. */
1492 status = _nx_dhcpv6_server_delete(dhcpv6_server_ptr);
1493
1494 /* Return commpletion status. */
1495 return(status);
1496 }
1497
1498
1499 /**************************************************************************/
1500 /* */
1501 /* FUNCTION RELEASE */
1502 /* */
1503 /* _nx_dhcpv6_client_delete PORTABLE C */
1504 /* 6.1 */
1505 /* AUTHOR */
1506 /* */
1507 /* Yuxin Zhou, Microsoft Corporation */
1508 /* */
1509 /* DESCRIPTION */
1510 /* */
1511 /* This function deletes the DHCPV6 Client instance and releases all of*/
1512 /* NetX and ThreadX resources. */
1513 /* */
1514 /* INPUT */
1515 /* */
1516 /* dhcpv6_server_ptr Pointer to Client instance */
1517 /* */
1518 /* OUTPUT */
1519 /* */
1520 /* NX_SUCCESS Successful Completion status */
1521 /* */
1522 /* CALLS */
1523 /* */
1524 /* nx_udp_socket_unbind Release DHCPV6 UDP socket port*/
1525 /* nx_udp_socket_delete Delete the DHCPV6 UDP socket */
1526 /* tx_thread_terminate Terminate DHCPV6 thread */
1527 /* tx_thread_delete Delete DHCPV6 thread */
1528 /* tx_timer_delete Delete DHCPV6 timers */
1529 /* tx_mutex_delete Delete DHCPV6 mutexes */
1530 /* tx_event_flags_delete Delete DHCPV6 flag queue */
1531 /* */
1532 /* CALLED BY */
1533 /* */
1534 /* Application Code */
1535 /* */
1536 /* RELEASE HISTORY */
1537 /* */
1538 /* DATE NAME DESCRIPTION */
1539 /* */
1540 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1541 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1542 /* resulting in version 6.1 */
1543 /* */
1544 /**************************************************************************/
_nx_dhcpv6_server_delete(NX_DHCPV6_SERVER * dhcpv6_server_ptr)1545 UINT _nx_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
1546 {
1547
1548 /* Terminate the DHCPV6 processing thread. */
1549 tx_thread_terminate(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread));
1550
1551 /* Delete the DHCPV6 processing thread. */
1552 tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread));
1553
1554 /* Delete the flag event queue. */
1555 tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events);
1556
1557 /* Delete the timers */
1558 tx_timer_delete(&(dhcpv6_server_ptr->nx_dhcpv6_lease_timer));
1559 tx_timer_delete(&(dhcpv6_server_ptr->nx_dhcpv6_session_timer));
1560
1561 /* Delete the mutexes. */
1562 tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex));
1563
1564 /* Release the UDP socket port. */
1565 nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket));
1566
1567 /* Delete the UDP socket. */
1568 nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket));
1569
1570 /* Clear the dhcpv6 structure ID. */
1571 dhcpv6_server_ptr -> nx_dhcpv6_id = 0;
1572
1573 /* Return a successful status. */
1574 return(NX_SUCCESS);
1575 }
1576
1577
1578 /**************************************************************************/
1579 /* */
1580 /* FUNCTION RELEASE */
1581 /* */
1582 /* _nxe_dhcpv6_create_ip_address_range PORTABLE C */
1583 /* 6.1 */
1584 /* AUTHOR */
1585 /* */
1586 /* Yuxin Zhou, Microsoft Corporation */
1587 /* */
1588 /* DESCRIPTION */
1589 /* */
1590 /* This function performs error checking on the create address list */
1591 /* service. */
1592 /* */
1593 /* INPUT */
1594 /* */
1595 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
1596 /* start_ipv6_address Start of IP address in list. */
1597 /* end_ipv6_address End of IP address in list. */
1598 /* addresses_added Number of addresses added to list*/
1599 /* */
1600 /* OUTPUT */
1601 /* */
1602 /* NX_SUCCESS Successful IP list creation */
1603 /* */
1604 /* CALLS */
1605 /* */
1606 /* nx_dhcpv6_create_ip_address_range Actual list create service */
1607 /* */
1608 /* CALLED BY */
1609 /* */
1610 /* Application code */
1611 /* */
1612 /* RELEASE HISTORY */
1613 /* */
1614 /* DATE NAME DESCRIPTION */
1615 /* */
1616 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1617 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1618 /* resulting in version 6.1 */
1619 /* */
1620 /**************************************************************************/
_nxe_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NXD_ADDRESS * start_ipv6_address,NXD_ADDRESS * end_ipv6_address,UINT * addresses_added)1621 UINT _nxe_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr,
1622 NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address,
1623 UINT *addresses_added)
1624 {
1625
1626 UINT status;
1627
1628
1629 /* Check for invalid input. */
1630 if ((dhcpv6_server_ptr == NX_NULL) ||
1631 (start_ipv6_address == NX_NULL)|| (end_ipv6_address == NX_NULL) ||
1632 (addresses_added == NX_NULL))
1633 {
1634 return(NX_PTR_ERROR);
1635 }
1636
1637 /* Check for invalid non pointer input. */
1638 if ((CHECK_UNSPECIFIED_ADDRESS(&start_ipv6_address -> nxd_ip_address.v6[0])) ||
1639 (CHECK_UNSPECIFIED_ADDRESS(&end_ipv6_address -> nxd_ip_address.v6[0])))
1640 {
1641
1642 return(NX_DHCPV6_INVALID_IP_ADDRESS);
1643 }
1644
1645 /* Check for an invalid address range. */
1646 if (start_ipv6_address -> nxd_ip_address.v6[3] > end_ipv6_address -> nxd_ip_address.v6[3])
1647 {
1648
1649 return(NX_DHCPV6_INVALID_IP_ADDRESS);
1650 }
1651
1652 status = _nx_dhcpv6_create_ip_address_range(dhcpv6_server_ptr, start_ipv6_address, end_ipv6_address, addresses_added);
1653
1654 return status;
1655 }
1656
1657
1658 /**************************************************************************/
1659 /* */
1660 /* FUNCTION RELEASE */
1661 /* */
1662 /* _nx_dhcpv6_create_ip_address_range PORTABLE C */
1663 /* 6.1 */
1664 /* AUTHOR */
1665 /* */
1666 /* Yuxin Zhou, Microsoft Corporation */
1667 /* */
1668 /* DESCRIPTION */
1669 /* */
1670 /* This function creates a list of IPv6 addresses the DHCPv6 server */
1671 /* may assign to clients, using a start and end address. It returns the*/
1672 /* number of addresses actually added, which may be limited by the size */
1673 /* of the server address table. */
1674 /* */
1675 /* Note: The NetX Duo DHCPv6 server accomodates up to 256 assignable */
1676 /* address ranges in the current release. */
1677 /* */
1678 /* INPUT */
1679 /* */
1680 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
1681 /* start_ipv6_address Start of IP address in list. */
1682 /* end_ipv6_address End of IP address in list. */
1683 /* addresses_added Number of addresses added to list*/
1684 /* */
1685 /* OUTPUT */
1686 /* */
1687 /* NX_SUCCESS Successful IP list creation */
1688 /* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */
1689 /* Supplied address not reachable */
1690 /* */
1691 /* CALLS */
1692 /* */
1693 /* */
1694 /* CALLED BY */
1695 /* */
1696 /* Application code */
1697 /* */
1698 /* RELEASE HISTORY */
1699 /* */
1700 /* DATE NAME DESCRIPTION */
1701 /* */
1702 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1703 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1704 /* resulting in version 6.1 */
1705 /* */
1706 /**************************************************************************/
_nx_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NXD_ADDRESS * start_ipv6_address,NXD_ADDRESS * end_ipv6_address,UINT * addresses_added)1707 UINT _nx_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr,
1708 NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address,
1709 UINT *addresses_added)
1710 {
1711
1712 UINT i;
1713 NX_IP *ip_ptr;
1714 UINT prefix_length;
1715 NXD_ADDRESS next_ipv6_address;
1716 UINT ga_address_index;
1717
1718
1719 *addresses_added = 0;
1720
1721 COPY_NXD_ADDRESS(start_ipv6_address, &next_ipv6_address);
1722
1723 /* Set up a local variable for convenience. */
1724 ip_ptr = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr;
1725 ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index;
1726 prefix_length = ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length;
1727
1728 /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the
1729 network masked addresses should be equal). */
1730 if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]),
1731 &start_ipv6_address -> nxd_ip_address.v6[0], prefix_length))
1732 {
1733
1734 return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS;
1735 }
1736
1737 if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]),
1738 &end_ipv6_address -> nxd_ip_address.v6[0], prefix_length))
1739 {
1740
1741 return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS;
1742 }
1743
1744 /* Set the server ip address based on the specified interface. */
1745
1746 /* Clear out existing entries and start adding IP addresses at the beginning of the list. */
1747 i = 0;
1748
1749 /* Fit as many IP addresses in the specified range as will fit in the table. */
1750 while (i < NX_DHCPV6_MAX_LEASES)
1751 {
1752
1753 NX_DHCPV6_ADDRESS_LEASE *ip_lease_ptr;
1754
1755 /* Set local pointer to the next entry for convenience. */
1756 ip_lease_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i];
1757
1758 /* Initialize each entry before adding data. */
1759 memset(&dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i], 0, sizeof(NX_DHCPV6_ADDRESS_LEASE));
1760
1761 /* Add the IP address into this slot. */
1762 COPY_NXD_ADDRESS(&next_ipv6_address, &ip_lease_ptr -> nx_dhcpv6_lease_IP_address);
1763
1764 /* Update the number of addresses added. */
1765 (*addresses_added)++;
1766
1767 /* Increase the address low word by one. */
1768 next_ipv6_address.nxd_ip_address.v6[3]++;
1769
1770 /* Check if we are overflowing the last word. */
1771 if (next_ipv6_address.nxd_ip_address.v6[3] == 0xFFFFFFFF)
1772 {
1773
1774 /* We are. Let's stop here. */
1775 break;
1776 }
1777
1778 if (CHECK_IPV6_ADDRESSES_SAME(&next_ipv6_address.nxd_ip_address.v6[0], &end_ipv6_address -> nxd_ip_address.v6[0]))
1779 {
1780 break;
1781 }
1782
1783 i++;
1784 }
1785
1786 /* Indicate how many addresses were actually added to the server list. */
1787 dhcpv6_server_ptr -> nx_dhcpv6_assignable_addresses = *addresses_added;
1788
1789 return(NX_SUCCESS);
1790 }
1791
1792
1793 /**************************************************************************/
1794 /* */
1795 /* FUNCTION RELEASE */
1796 /* */
1797 /* _nxe_dhcpv6_reserve_ip_address_range PORTABLE C */
1798 /* 6.1 */
1799 /* AUTHOR */
1800 /* */
1801 /* Yuxin Zhou, Microsoft Corporation */
1802 /* */
1803 /* DESCRIPTION */
1804 /* */
1805 /* This function performs error checking on the reserve address list */
1806 /* service. */
1807 /* */
1808 /* INPUT */
1809 /* */
1810 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
1811 /* start_ipv6_address Start of IP address to reserve */
1812 /* end_ipv6_address End of IP address to reserve */
1813 /* addresses_reserved Number of addresses reserved */
1814 /* */
1815 /* OUTPUT */
1816 /* */
1817 /* NX_SUCCESS Successful IP list creation */
1818 /* NX_DHCPV6_INVALID_IP_ADDRESS Invalid address supplied */
1819 /* */
1820 /* CALLS */
1821 /* */
1822 /* nx_dhcpv6_reserve_ip_address_range Actual list create service */
1823 /* */
1824 /* CALLED BY */
1825 /* */
1826 /* Application code */
1827 /* */
1828 /* RELEASE HISTORY */
1829 /* */
1830 /* DATE NAME DESCRIPTION */
1831 /* */
1832 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1833 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1834 /* resulting in version 6.1 */
1835 /* */
1836 /**************************************************************************/
_nxe_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NXD_ADDRESS * start_ipv6_address,NXD_ADDRESS * end_ipv6_address,UINT * addresses_reserved)1837 UINT _nxe_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr,
1838 NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address,
1839 UINT *addresses_reserved)
1840 {
1841
1842 UINT status;
1843
1844
1845 /* Check for invalid input. */
1846 if ((dhcpv6_server_ptr == NX_NULL) ||
1847 (start_ipv6_address == NX_NULL)|| (end_ipv6_address == NX_NULL) ||
1848 (addresses_reserved == NX_NULL))
1849 {
1850 return(NX_PTR_ERROR);
1851 }
1852
1853 /* Check for invalid non pointer input. */
1854 if (start_ipv6_address -> nxd_ip_address.v6[3] > end_ipv6_address -> nxd_ip_address.v6[3])
1855 {
1856
1857 return(NX_DHCPV6_INVALID_IP_ADDRESS);
1858 }
1859
1860 if ((CHECK_UNSPECIFIED_ADDRESS(&start_ipv6_address -> nxd_ip_address.v6[0])) ||
1861 (CHECK_UNSPECIFIED_ADDRESS(&end_ipv6_address -> nxd_ip_address.v6[0])))
1862 {
1863 return(NX_DHCPV6_INVALID_IP_ADDRESS);
1864 }
1865
1866 status = _nx_dhcpv6_reserve_ip_address_range(dhcpv6_server_ptr, start_ipv6_address, end_ipv6_address, addresses_reserved);
1867
1868 return status;
1869 }
1870
1871
1872 /**************************************************************************/
1873 /* */
1874 /* FUNCTION RELEASE */
1875 /* */
1876 /* _nx_dhcpv6_reserve_ip_address_range PORTABLE C */
1877 /* 6.1 */
1878 /* AUTHOR */
1879 /* */
1880 /* Yuxin Zhou, Microsoft Corporation */
1881 /* */
1882 /* DESCRIPTION */
1883 /* */
1884 /* This function reserves a range of IPv6 addresses not to assign to */
1885 /* Clients, using a start and end address. It returns the number of */
1886 /* addresses actually reserved, depending on the size of the server */
1887 /* address table. To reserve a single address, start and end address */
1888 /* are the same. */
1889 /* */
1890 /* INPUT */
1891 /* */
1892 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
1893 /* start_ipv6_address Start of IP address in list. */
1894 /* end_ipv6_address End of IP address in list. */
1895 /* addresses_reserved Number of addresses reserved */
1896 /* */
1897 /* OUTPUT */
1898 /* */
1899 /* NX_SUCCESS Successful IP address reservation*/
1900 /* NX_DHCPV6_INVALID_IP_ADDRESS Reserved addresses out of range */
1901 /* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */
1902 /* Supplied address is unreachable */
1903 /* */
1904 /* CALLS */
1905 /* */
1906 /* CHECK_IP_ADDRESSES_BY_PREFIX Confirm addresses match the */
1907 /* server domain by matching prefix*/
1908 /* */
1909 /* CALLED BY */
1910 /* */
1911 /* Application code */
1912 /* */
1913 /* RELEASE HISTORY */
1914 /* */
1915 /* DATE NAME DESCRIPTION */
1916 /* */
1917 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1918 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1919 /* resulting in version 6.1 */
1920 /* */
1921 /**************************************************************************/
_nx_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NXD_ADDRESS * start_ipv6_address,NXD_ADDRESS * end_ipv6_address,UINT * addresses_reserved)1922 UINT _nx_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr,
1923 NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address,
1924 UINT *addresses_reserved)
1925 {
1926
1927 UINT i;
1928 NX_IP *ip_ptr;
1929 UINT prefix_length;
1930 NXD_ADDRESS next_ipv6_address;
1931 NX_DHCPV6_ADDRESS_LEASE *ip_lease_ptr = NX_NULL;
1932 UINT ga_address_index;
1933
1934
1935 /* Initialize local and input variables. */
1936 *addresses_reserved = 0;
1937
1938 COPY_NXD_ADDRESS(start_ipv6_address, &next_ipv6_address);
1939
1940 /* Set up a local variable for convenience. */
1941 ip_ptr = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr;
1942 ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index;
1943 prefix_length = ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length;
1944
1945 /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the
1946 network masked addresses should be equal). */
1947 if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]),
1948 &start_ipv6_address -> nxd_ip_address.v6[0], prefix_length))
1949 {
1950
1951 return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS;
1952 }
1953
1954 if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]),
1955 &end_ipv6_address -> nxd_ip_address.v6[0], prefix_length))
1956 {
1957
1958 return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS;
1959 }
1960
1961 /* Clear out existing entries and start adding IP addresses at the beginning of the list. */
1962 i = 0;
1963
1964 /* Match on start-end addresses for which leases to reserve. */
1965 while (i < NX_DHCPV6_MAX_LEASES)
1966 {
1967
1968 /* Set local pointer to the entry for convenience. */
1969 ip_lease_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i];
1970
1971 /* Add the IP address into this slot. */
1972 COPY_NXD_ADDRESS(&next_ipv6_address, &ip_lease_ptr -> nx_dhcpv6_lease_IP_address);
1973
1974 /* Check if we found the starting address. */
1975 if (CHECK_IPV6_ADDRESSES_SAME(&ip_lease_ptr -> nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0], &start_ipv6_address -> nxd_ip_address.v6[0]))
1976 {
1977 break;
1978 }
1979 }
1980
1981 if (i == NX_DHCPV6_MAX_LEASES)
1982 {
1983
1984 /* No starting address found in the server IP address list. */
1985 return NX_DHCPV6_INVALID_IP_ADDRESS;
1986 }
1987
1988 /* Set the lease times of this entry to infinity. */
1989 ip_lease_ptr -> nx_dhcpv6_lease_T1_lifetime = NX_DHCPV6_INFINTY_LEASE;
1990 ip_lease_ptr -> nx_dhcpv6_lease_T2_lifetime = NX_DHCPV6_INFINTY_LEASE;
1991 ip_lease_ptr -> nx_dhcpv6_lease_valid_lifetime = NX_DHCPV6_INFINTY_LEASE;
1992 ip_lease_ptr -> nx_dhcpv6_lease_preferred_lifetime = NX_DHCPV6_INFINTY_LEASE;
1993 ip_lease_ptr -> nx_dhcpv6_lease_assigned_to = (NX_DHCPV6_CLIENT *)(ALIGN_TYPE)0xFFFFFFFF;
1994
1995 /* Update the number of addresses reserved. */
1996 (*addresses_reserved)++;
1997
1998 /* Process the next entry. */
1999
2000 /* We found the starting address, so start reserving the rest of the address(es). */
2001 while ((!CHECK_IPV6_ADDRESSES_SAME(&next_ipv6_address.nxd_ip_address.v6[0], &end_ipv6_address -> nxd_ip_address.v6[0])) &&
2002 (i < NX_DHCPV6_MAX_LEASES))
2003 {
2004
2005 i++;
2006
2007 /* Set local pointer to the next entry for convenience. */
2008 ip_lease_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i];
2009
2010 /* Set the lease times of this entry to infinity. */
2011 ip_lease_ptr -> nx_dhcpv6_lease_T1_lifetime = NX_DHCPV6_INFINTY_LEASE;
2012 ip_lease_ptr -> nx_dhcpv6_lease_T2_lifetime = NX_DHCPV6_INFINTY_LEASE;
2013 ip_lease_ptr -> nx_dhcpv6_lease_valid_lifetime = NX_DHCPV6_INFINTY_LEASE;
2014 ip_lease_ptr -> nx_dhcpv6_lease_preferred_lifetime = NX_DHCPV6_INFINTY_LEASE;
2015
2016 /* Set the number of addresses actually reserved. */
2017 (*addresses_reserved)++;
2018
2019 /* Return a pointer to the beginning of non reserved addresses.*/
2020 COPY_NXD_ADDRESS(&ip_lease_ptr -> nx_dhcpv6_lease_IP_address, &next_ipv6_address);
2021 }
2022
2023 return(NX_SUCCESS);
2024 }
2025
2026
2027 /**************************************************************************/
2028 /* */
2029 /* FUNCTION RELEASE */
2030 /* */
2031 /* _nxe_dhcpv6_create_dns_address PORTABLE C */
2032 /* 6.1 */
2033 /* AUTHOR */
2034 /* */
2035 /* Yuxin Zhou, Microsoft Corporation */
2036 /* */
2037 /* DESCRIPTION */
2038 /* */
2039 /* This function does error checking for the add dns address service. */
2040 /* */
2041 /* INPUT */
2042 /* */
2043 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
2044 /* dns_ipv6_address DNS server IP address */
2045 /* */
2046 /* OUTPUT */
2047 /* */
2048 /* NX_DHCPV6_PARAM_ERROR Invalid input */
2049 /* status Actual add dns address status */
2050 /* */
2051 /* CALLS */
2052 /* */
2053 /* _nx_dhcpv6_create_dns_address */
2054 /* Add DNS server address service */
2055 /* CALLED BY */
2056 /* */
2057 /* Application code */
2058 /* */
2059 /* RELEASE HISTORY */
2060 /* */
2061 /* DATE NAME DESCRIPTION */
2062 /* */
2063 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2064 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2065 /* resulting in version 6.1 */
2066 /* */
2067 /**************************************************************************/
_nxe_dhcpv6_create_dns_address(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NXD_ADDRESS * dns_ipv6_address)2068 UINT _nxe_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address)
2069 {
2070
2071 UINT status;
2072
2073
2074 /* Check for invalid pointer input. */
2075 if (!dhcpv6_server_ptr || !dns_ipv6_address)
2076 {
2077 return NX_PTR_ERROR;
2078 }
2079
2080 /* Check for invalid parameters and null address. */
2081 if ((dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID) ||
2082 (CHECK_UNSPECIFIED_ADDRESS(&dns_ipv6_address -> nxd_ip_address.v6[0])))
2083
2084 {
2085 return NX_DHCPV6_PARAM_ERROR;
2086 }
2087
2088 status = _nx_dhcpv6_create_dns_address(dhcpv6_server_ptr, dns_ipv6_address);
2089
2090 return status;
2091 }
2092
2093
2094 /**************************************************************************/
2095 /* */
2096 /* FUNCTION RELEASE */
2097 /* */
2098 /* _nx_dhcpv6_create_dns_address PORTABLE C */
2099 /* 6.1 */
2100 /* AUTHOR */
2101 /* */
2102 /* Yuxin Zhou, Microsoft Corporation */
2103 /* */
2104 /* DESCRIPTION */
2105 /* */
2106 /* This function the DNS server address to the DHCPv6 server for when */
2107 /* clients request the DNS server address. */
2108 /* */
2109 /* INPUT */
2110 /* */
2111 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
2112 /* dns_ipv6_address DNS server IP address */
2113 /* */
2114 /* OUTPUT */
2115 /* */
2116 /* NX_SUCCESS Successfully added dns address */
2117 /* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */
2118 /* DNS prefix does not match */
2119 /* DHCPv6 server interface */
2120 /* */
2121 /* CALLS */
2122 /* */
2123 /* */
2124 /* CALLED BY */
2125 /* */
2126 /* Application code */
2127 /* */
2128 /* RELEASE HISTORY */
2129 /* */
2130 /* DATE NAME DESCRIPTION */
2131 /* */
2132 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2133 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2134 /* resulting in version 6.1 */
2135 /* */
2136 /**************************************************************************/
_nx_dhcpv6_create_dns_address(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NXD_ADDRESS * dns_ipv6_address)2137 UINT _nx_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address)
2138 {
2139
2140 NX_IP *ip_ptr;
2141 UINT prefix_length;
2142 UINT ga_address_index;
2143
2144
2145 /* Set up local variables for convenience. */
2146 ip_ptr = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr;
2147 ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index;
2148 prefix_length = ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length;
2149
2150 /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the
2151 network masked addresses should be equal). */
2152 if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]),
2153 &dns_ipv6_address -> nxd_ip_address.v6[0],
2154 prefix_length))
2155 {
2156
2157 return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS;
2158 }
2159
2160 /* Set the dns server for this interface. */
2161 COPY_NXD_ADDRESS(dns_ipv6_address, &dhcpv6_server_ptr -> nx_dhcpv6_dns_ip_address);
2162
2163 return(NX_SUCCESS);
2164 }
2165
2166
2167 /**************************************************************************/
2168 /* */
2169 /* FUNCTION RELEASE */
2170 /* */
2171 /* _nxe_dhcpv6_set_server_duid PORTABLE C */
2172 /* 6.1 */
2173 /* AUTHOR */
2174 /* */
2175 /* Yuxin Zhou, Microsoft Corporation */
2176 /* */
2177 /* DESCRIPTION */
2178 /* */
2179 /* This function performs error checking for the create server DUID */
2180 /* service. */
2181 /* */
2182 /* INPUT */
2183 /* */
2184 /* dhcpv6_server_ptr Pointer to DHCPv6 server instance */
2185 /* duid_type Type of DUID, e.g. LL or LLT */
2186 /* hardware_type Network hardware type e.g IEEE 802*/
2187 /* mac_address_msw Mac address most significant bit */
2188 /* mac_address_lsw Mac address least significant bit */
2189 /* time Time data for link layer DUIDs */
2190 /* */
2191 /* OUTPUT */
2192 /* */
2193 /* status Actual completion status */
2194 /* NX_SUCCESS Successful completion status */
2195 /* */
2196 /* CALLS */
2197 /* */
2198 /* _nx_dhcpv6_set_server_duid Actual create server duid service */
2199 /* */
2200 /* CALLED BY */
2201 /* */
2202 /* Application Code */
2203 /* */
2204 /* RELEASE HISTORY */
2205 /* */
2206 /* DATE NAME DESCRIPTION */
2207 /* */
2208 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2209 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2210 /* resulting in version 6.1 */
2211 /* */
2212 /**************************************************************************/
_nxe_dhcpv6_set_server_duid(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT duid_type,UINT hardware_type,ULONG mac_address_msw,ULONG mac_address_lsw,ULONG time)2213 UINT _nxe_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type,
2214 ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time)
2215 {
2216 UINT status;
2217
2218
2219 /* Check for invalid pointer input. */
2220 if (dhcpv6_server_ptr == NX_NULL)
2221 {
2222 return NX_PTR_ERROR;
2223 }
2224
2225 /* For link layer time DUIDs, the time input must be non zero. */
2226 if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME)
2227 {
2228 if (time == 0)
2229 {
2230 return NX_PTR_ERROR;
2231
2232 }
2233 }
2234
2235 /* Check for invalid non pointer input. */
2236 if ((duid_type == 0) || (hardware_type == 0) || (mac_address_msw == 0) || (mac_address_lsw == 0))
2237 {
2238 return NX_INVALID_PARAMETERS;
2239 }
2240
2241 /* Call the actual service. */
2242 status = _nx_dhcpv6_set_server_duid(dhcpv6_server_ptr, duid_type, hardware_type, mac_address_msw, mac_address_lsw, time);
2243
2244 return status;
2245 }
2246
2247
2248 /**************************************************************************/
2249 /* */
2250 /* FUNCTION RELEASE */
2251 /* */
2252 /* _nx_dhcpv6_set_server_duid PORTABLE C */
2253 /* 6.1 */
2254 /* AUTHOR */
2255 /* */
2256 /* Yuxin Zhou, Microsoft Corporation */
2257 /* */
2258 /* DESCRIPTION */
2259 /* */
2260 /* This function creates the server DUID with the input data. */
2261 /* */
2262 /* INPUT */
2263 /* */
2264 /* dhcpv6_server_ptr Pointer to DHCPv6 server instance */
2265 /* duid_type Type of DUID, e.g. LL or LLT */
2266 /* hardware_type Network hardware type e.g IEEE 802*/
2267 /* mac_address_msw Mac address most significant bit */
2268 /* mac_address_lsw Mac address least significant bit */
2269 /* time Time data for link layer DUIDs */
2270 /* */
2271 /* OUTPUT */
2272 /* */
2273 /* status Actual completion status */
2274 /* NX_SUCCESS Successful completion status */
2275 /* NX_DHCPV6_BAD_SERVER_DUID Unknown or invalid DUID type */
2276 /* NX_DHCPV6_INVALID_VENDOR_DATA Invalid Vendor ID supplied */
2277 /* */
2278 /* CALLS */
2279 /* */
2280 /* memset Clear specified area of memory */
2281 /* memcpy Copy data to specified location */
2282 /* */
2283 /* CALLED BY */
2284 /* */
2285 /* Application Code */
2286 /* */
2287 /* RELEASE HISTORY */
2288 /* */
2289 /* DATE NAME DESCRIPTION */
2290 /* */
2291 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2292 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2293 /* verified memcpy use cases, */
2294 /* resulting in version 6.1 */
2295 /* */
2296 /**************************************************************************/
_nx_dhcpv6_set_server_duid(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT duid_type,UINT hardware_type,ULONG mac_address_msw,ULONG mac_address_lsw,ULONG time)2297 UINT _nx_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type,
2298 ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time)
2299 {
2300
2301 NX_DHCPV6_SVR_DUID *duid_ptr;
2302
2303
2304 duid_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_server_duid;
2305
2306 /* Initialize the DUID to null. */
2307 memset(duid_ptr, 0, sizeof(NX_DHCPV6_SVR_DUID));
2308
2309 /* Assign the DUID op code. */
2310 duid_ptr -> nx_op_code = NX_DHCPV6_OP_DUID_SERVER;
2311
2312 /* Set the DUID type. */
2313 duid_ptr -> nx_duid_type = (USHORT)duid_type;
2314
2315 /* Set the DUID data for a non vendor DUID. */
2316 if (duid_ptr -> nx_duid_type != NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED)
2317 {
2318
2319 /* Server has a valid link local address. Add this to the server DUID fields
2320 if not a vendor assigned DUID type. */
2321 duid_ptr-> nx_link_layer_address_msw = (USHORT)mac_address_msw;
2322 duid_ptr -> nx_link_layer_address_lsw = mac_address_lsw;
2323
2324 /* Set the hardware type. */
2325 duid_ptr -> nx_hardware_type = (USHORT)hardware_type;
2326 }
2327 else
2328 {
2329 /* This is a private vendor DUID with private vendor ID. */
2330 duid_ptr -> nx_duid_enterprise_number = NX_DHCPV6_SERVER_DUID_VENDOR_PRIVATE_ID;
2331
2332 /* Check that the server vendor ID size. */
2333 if (sizeof(NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID) > NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH)
2334 {
2335 return NX_DHCPV6_INVALID_VENDOR_DATA;
2336 }
2337
2338 memcpy(&duid_ptr -> nx_duid_private_identifier[0], NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID, sizeof(NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID)); /* Use case of memcpy is verified. */
2339 }
2340
2341 /* Now set the server DUID length. This will depend on DUID type. */
2342 if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY)
2343 {
2344
2345 /* Set the length to include the duid type, hardware type, msw and lsw fields. */
2346 duid_ptr -> nx_option_length = 3 * sizeof(USHORT) + sizeof(ULONG);
2347 }
2348 else if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME)
2349 {
2350
2351 /* Set the length to include the duid type, hardware type, time, and msw and lsw fields. */
2352 duid_ptr -> nx_option_length = 3 * sizeof(USHORT) + 2 * sizeof(ULONG);
2353
2354 /* Set the DUID time. */
2355 duid_ptr -> nx_duid_time = time;
2356
2357 }
2358 else if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED)
2359 {
2360
2361 /* Set the length to include the duid type, hardware type, enterprise number and
2362 variable length private identifier. */
2363 duid_ptr -> nx_option_length = sizeof(USHORT) + sizeof(ULONG) + sizeof(NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID);
2364 }
2365 else
2366 {
2367
2368 /* Undefined or unknown DUID type. Return error status. */
2369 return NX_DHCPV6_BAD_SERVER_DUID;
2370 }
2371
2372 return NX_SUCCESS;
2373 }
2374
2375
2376 /**************************************************************************/
2377 /* */
2378 /* FUNCTION RELEASE */
2379 /* */
2380 /* _nx_dhcpv6_prepare_iana_status PORTABLE C */
2381 /* 6.1 */
2382 /* AUTHOR */
2383 /* */
2384 /* Yuxin Zhou, Microsoft Corporation */
2385 /* */
2386 /* DESCRIPTION */
2387 /* */
2388 /* This function updates the IANA status option. If the flag input is */
2389 /* set, the standard server status message is added to the */
2390 /* message buffer, and the option length updated. If the flag is false,*/
2391 /* no message is sent with the status option. */
2392 /* */
2393 /* INPUT */
2394 /* */
2395 /* dhcpv6_status_ptr Pointer to IANA status to add */
2396 /* flag 0 to clear; 1 to add message */
2397 /* */
2398 /* OUTPUT */
2399 /* */
2400 /* NX_SUCCESS Successful completion status */
2401 /* */
2402 /* CALLS */
2403 /* */
2404 /* memcpy Copy specified area of memory */
2405 /* */
2406 /* CALLED BY */
2407 /* */
2408 /* _nx_dhcpv6_send_response_to_client Send server response to client */
2409 /* */
2410 /* RELEASE HISTORY */
2411 /* */
2412 /* DATE NAME DESCRIPTION */
2413 /* */
2414 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2415 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2416 /* verified memcpy use cases, */
2417 /* resulting in version 6.1 */
2418 /* */
2419 /**************************************************************************/
_nx_dhcpv6_prepare_iana_status(NX_DHCPV6_SERVER_IANA_STATUS * dhcpv6_status_ptr,UINT flag)2420 UINT _nx_dhcpv6_prepare_iana_status(NX_DHCPV6_SERVER_IANA_STATUS *dhcpv6_status_ptr, UINT flag)
2421 {
2422
2423
2424 /* Make sure the basic header fields are filled in. No need to check the status code has been set; it is
2425 part of the decision to send a response. */
2426 dhcpv6_status_ptr -> nx_op_code = NX_DHCPV6_OP_OPTION_STATUS;
2427 dhcpv6_status_ptr -> nx_option_length = sizeof(USHORT);
2428
2429 /* Check if we are adding or clearing a message. */
2430 if (flag == NX_FALSE)
2431 {
2432
2433 /* Clear the message. */
2434 memset(&dhcpv6_status_ptr -> nx_status_message[0], 0, NX_DHCPV6_STATUS_MESSAGE_MAX);
2435
2436 /*We're done! */
2437 return NX_SUCCESS;
2438 }
2439
2440 /* Flag is set so we are adding a message into the packet. */
2441
2442 /* Clear the message before adding anything into the message buffer. */
2443 memset(&dhcpv6_status_ptr -> nx_status_message[0], 0, NX_DHCPV6_STATUS_MESSAGE_MAX);
2444
2445 /* Fill in message according to status code. */
2446 switch (dhcpv6_status_ptr -> nx_status_code)
2447 {
2448
2449 case NX_DHCPV6_STATUS_SUCCESS:
2450
2451 /* Copy the standard server reply to message buffer. */
2452 memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_SUCCESS, sizeof(NX_DHCPV6_STATUS_MESSAGE_SUCCESS)); /* Use case of memcpy is verified. */
2453
2454 /* Update the option length. */
2455 dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_SUCCESS));
2456
2457 /* We're done! */
2458 break;
2459
2460 case NX_DHCPV6_STATUS_UNSPECIFIED:
2461
2462 /* Copy the standard server reply to message buffer. */
2463 memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED, sizeof(NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED)); /* Use case of memcpy is verified. */
2464
2465 /* Update the option length. */
2466 dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED));
2467
2468 /* We're done! */
2469 break;
2470
2471 case NX_DHCPV6_STATUS_NO_ADDRS_AVAILABLE:
2472
2473 /* Copy the standard server reply to message buffer. */
2474 memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE, sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE)); /* Use case of memcpy is verified. */
2475
2476 /* Update the option length. */
2477 dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE));
2478
2479 /* We're done! */
2480 break;
2481
2482 case NX_DHCPV6_STATUS_NO_BINDING:
2483
2484 /* Copy the standard server reply to message buffer. */
2485 memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_NO_BINDING, sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_BINDING)); /* Use case of memcpy is verified. */
2486
2487 /* Update the option length. */
2488 dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_BINDING));
2489
2490 /* We're done! */
2491 break;
2492
2493 case NX_DHCPV6_STATUS_NOT_ON_LINK:
2494
2495 /* Copy the standard server reply to message buffer. */
2496 memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK, sizeof(NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK)); /* Use case of memcpy is verified. */
2497
2498 /* Update the option length. */
2499 dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK));
2500
2501 /* We're done! */
2502 break;
2503
2504 case NX_DHCPV6_STATUS_USE_MULTICAST:
2505
2506 /* Copy the standard server reply to message buffer. */
2507 memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST, sizeof(NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST)); /* Use case of memcpy is verified. */
2508
2509 /* Update the option length. */
2510 dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST));
2511
2512 /* We're done! */
2513 break;
2514
2515
2516 default:
2517 break;
2518 }
2519
2520 return NX_SUCCESS;
2521 }
2522
2523
2524 /**************************************************************************/
2525 /* */
2526 /* FUNCTION RELEASE */
2527 /* */
2528 /* _nx_dhcpv6_add_preference PORTABLE C */
2529 /* 6.1 */
2530 /* AUTHOR */
2531 /* */
2532 /* Yuxin Zhou, Microsoft Corporation */
2533 /* */
2534 /* DESCRIPTION */
2535 /* */
2536 /* This function adds a DHCPv6 preference option to the server reply. */
2537 /* */
2538 /* */
2539 /* INPUT */
2540 /* */
2541 /* dhcpv6_server_ptr Pointer to DHCPv6 Server instance */
2542 /* dhcpv6_client_ptr Pointer to DHCPv6 Client instance */
2543 /* index Location where to write the data */
2544 /* */
2545 /* OUTPUT */
2546 /* */
2547 /* NX_SUCCESS Successful completion status */
2548 /* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */
2549 /* Data too large for packet payload */
2550 /* */
2551 /* CALLS */
2552 /* */
2553 /* memcpy Copy specified area of memory */
2554 /* */
2555 /* CALLED BY */
2556 /* */
2557 /* _nx_dhcpv6_send_response_to_client Send server response to client */
2558 /* */
2559 /* RELEASE HISTORY */
2560 /* */
2561 /* DATE NAME DESCRIPTION */
2562 /* */
2563 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2564 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2565 /* verified memcpy use cases, */
2566 /* resulting in version 6.1 */
2567 /* */
2568 /**************************************************************************/
_nx_dhcpv6_add_preference(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_CLIENT * dhcpv6_client_ptr,UCHAR * buffer_ptr,UINT * index)2569 UINT _nx_dhcpv6_add_preference(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index)
2570 {
2571
2572 UINT available_payload;
2573 ULONG message_word;
2574
2575
2576 /* Fill in option code and length. */
2577 dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_op_code = NX_DHCPV6_OP_PREFERENCE;
2578 dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_option_length = 1;
2579 dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_pref_value = NX_DHCPV6_PREFERENCE_VALUE;
2580
2581 /* Compute the available payload in the packet buffer. */
2582 available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size -
2583 NX_IPv6_UDP_PACKET - *index;
2584
2585 /* Check if the DUID will fit in the packet buffer. */
2586 if (available_payload < (UINT)(dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_option_length + 4))
2587 {
2588
2589 /* It won't! */
2590 return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD;
2591 }
2592
2593 /* Create the word to write to the buffer. */
2594 message_word = (ULONG)dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_op_code << 16;
2595 message_word |= dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_option_length;
2596
2597 /* Adjust for endianness. */
2598 NX_CHANGE_ULONG_ENDIAN(message_word);
2599
2600 /* Copy first half of the DUID option to packet buffer. */
2601 memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); /* Use case of memcpy is verified. */
2602
2603 *index += (ULONG)sizeof(ULONG);
2604
2605 /* Set the preference value. */
2606 *(buffer_ptr + *index) = (UCHAR)(dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_pref_value);
2607
2608 (*index)++;
2609
2610 return NX_SUCCESS;
2611 }
2612
2613
2614 /**************************************************************************/
2615 /* */
2616 /* FUNCTION RELEASE */
2617 /* */
2618 /* _nx_dhcpv6_add_option_requests PORTABLE C */
2619 /* 6.1 */
2620 /* AUTHOR */
2621 /* */
2622 /* Yuxin Zhou, Microsoft Corporation */
2623 /* */
2624 /* DESCRIPTION */
2625 /* */
2626 /* This function adds the 'option request' option to the server reply */
2627 /* packet based on the options requested from the client, and what */
2628 /* options the DHCPv6 server is configured to supply. */
2629 /* */
2630 /* INPUT */
2631 /* */
2632 /* dhcpv6_server_ptr Pointer to DHCPV6 server instance */
2633 /* dhcpv6_client_ptr Pointer to DHCPV6 client instance */
2634 /* buffer_ptr Pointer to packet buffer */
2635 /* index Location into buffer to write data*/
2636 /* */
2637 /* OUTPUT */
2638 /* */
2639 /* NX_SUCCESS Successful completion status */
2640 /* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */
2641 /* Not enough room for the option */
2642 /* request in the packet payload */
2643 /* CALLS */
2644 /* */
2645 /* memset Clears specified area of memory */
2646 /* memcpy Copies specified area of memory */
2647 /* */
2648 /* CALLED BY */
2649 /* */
2650 /* _nx_dhcpv6_send_request Compiles and sends the server */
2651 /* DHCPv6 response */
2652 /* */
2653 /* RELEASE HISTORY */
2654 /* */
2655 /* DATE NAME DESCRIPTION */
2656 /* */
2657 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2658 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2659 /* verified memcpy use cases, */
2660 /* resulting in version 6.1 */
2661 /* */
2662 /**************************************************************************/
_nx_dhcpv6_add_option_requests(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_CLIENT * dhcpv6_client_ptr,UCHAR * buffer_ptr,UINT * index)2663 UINT _nx_dhcpv6_add_option_requests(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr,
2664 UCHAR *buffer_ptr, UINT *index)
2665 {
2666
2667 USHORT i, j;
2668 ULONG message_word;
2669 UINT available_payload;
2670 NXD_ADDRESS *dns_server_address;
2671 NX_DHCPV6_SERVER_OPTIONREQUEST *dhcpv6_option_ptr;
2672
2673
2674 dhcpv6_option_ptr = &dhcpv6_client_ptr -> nx_dhcpv6_option_request;
2675
2676 /* Compute the available payload in the packet buffer. */
2677 available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size -
2678 NX_IPv6_UDP_PACKET - *index;
2679
2680 /* Process up to the maximum allowed options. */
2681 for(i = 0; i < NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS; i++)
2682 {
2683
2684 /* Check for the end of the list. */
2685 if (dhcpv6_option_ptr -> nx_op_request[i] == 0)
2686 {
2687
2688 /* No more options. */
2689 break;
2690 }
2691
2692 /* Is this the DNS server option? */
2693 if (dhcpv6_option_ptr -> nx_op_request[i] == NX_DHCPV6_RFC_DNS_SERVER_OPTION)
2694 {
2695
2696 /* Create an option containing a single DNS server address. */
2697 dhcpv6_option_ptr -> nx_option_length = 4 * sizeof(ULONG);
2698
2699 /* Check if the option request option will fit in the packet buffer. */
2700 if (available_payload < (UINT)(dhcpv6_option_ptr -> nx_option_length + 4))
2701 {
2702
2703 /* It won't. */
2704 return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD;
2705 }
2706
2707 message_word = (ULONG)dhcpv6_option_ptr -> nx_op_request[i] << 16;
2708 message_word |= dhcpv6_option_ptr -> nx_option_length;
2709
2710 /* Adjust for endianness. */
2711 NX_CHANGE_ULONG_ENDIAN(message_word);
2712
2713 /* Copy the option request option header to the packet. */
2714 memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); /* Use case of memcpy is verified. */
2715 *index += (ULONG)sizeof(ULONG);
2716
2717 dns_server_address = &dhcpv6_server_ptr -> nx_dhcpv6_dns_ip_address;
2718 for (j = 0; j < 4; j++)
2719 {
2720
2721 message_word = dns_server_address -> nxd_ip_address.v6[j];
2722
2723 NX_CHANGE_ULONG_ENDIAN(message_word);
2724
2725 memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); /* Use case of memcpy is verified. */
2726
2727 *index += (ULONG)sizeof(ULONG);
2728 }
2729
2730 /* Update the available payload. */
2731 available_payload = (UINT)(available_payload - (UINT)(dhcpv6_option_ptr -> nx_option_length + 4));
2732 }
2733 /* Does the DHCPv6 server have an extended option handler? */
2734 else if (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler_extended)
2735 {
2736
2737 /* Yes, so call it. This handler shall fill the buffer with the requested
2738 option data (if available).
2739
2740 Note: The handler must update the index pointing to the end of data in the buffer
2741 after it inserts the data. This is done for the DNS server option above. */
2742 (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler_extended)(dhcpv6_server_ptr, dhcpv6_option_ptr -> nx_op_request[i], buffer_ptr, index, available_payload);
2743
2744 /* Check if exceed the payload. */
2745 if ((NX_IPv6_UDP_PACKET + *index) <= dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size)
2746 {
2747
2748 /* Update the available payload. */
2749 available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size -
2750 NX_IPv6_UDP_PACKET - *index;
2751 }
2752 else
2753 {
2754 return (NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD);
2755 }
2756 }
2757 /* Does the DHCPv6 server have an option handler? */
2758 else if (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler)
2759 {
2760
2761 /* Yes, so call it. This handler shall fill the buffer with the requested
2762 option data (if available).
2763
2764 Note: The handler must update the index pointing to the end of data in the buffer
2765 after it inserts the data. This is done for the DNS server option above. */
2766 (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler)(dhcpv6_server_ptr, dhcpv6_option_ptr -> nx_op_request[i], buffer_ptr, index);
2767
2768 /* Check if exceed the payload. */
2769 if ((NX_IPv6_UDP_PACKET + *index) <= dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size)
2770 {
2771
2772 /* Update the available payload. */
2773 available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size -
2774 NX_IPv6_UDP_PACKET - *index;
2775 }
2776 else
2777 {
2778 return (NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD);
2779 }
2780
2781 }
2782 }
2783
2784 return NX_SUCCESS;
2785 }
2786
2787
2788 /**************************************************************************/
2789 /* */
2790 /* FUNCTION RELEASE */
2791 /* */
2792 /* _nxe_dhcpv6_server_interface_set PORTABLE C */
2793 /* 6.1 */
2794 /* AUTHOR */
2795 /* */
2796 /* Yuxin Zhou, Microsoft Corporation */
2797 /* */
2798 /* DESCRIPTION */
2799 /* */
2800 /* This function performs error checking on the set interface service. */
2801 /* */
2802 /* INPUT */
2803 /* */
2804 /* dhcpv6_server_ptr Pointer to the DHCPV6 Server */
2805 /* iface_index Physical interface index for */
2806 /* DHCP communication */
2807 /* ga_address_index Global address index on DHCPv6*/
2808 /* interface */
2809 /* */
2810 /* OUTPUT */
2811 /* */
2812 /* NX_PTR_ERROR Invalid pointer input */
2813 /* NX_INVALID_INTERFACE Invalid interface index */
2814 /* NX_NO_INTERFACE_ADDRESS Invalid global address index */
2815 /* */
2816 /* CALLS */
2817 /* */
2818 /* _nx_dhcpv6_server_interface_set Actual set interfaces service */
2819 /* */
2820 /* CALLED BY */
2821 /* */
2822 /* Application Code */
2823 /* */
2824 /* RELEASE HISTORY */
2825 /* */
2826 /* DATE NAME DESCRIPTION */
2827 /* */
2828 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2829 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2830 /* resulting in version 6.1 */
2831 /* */
2832 /**************************************************************************/
_nxe_dhcpv6_server_interface_set(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT iface_index,UINT ga_address_index)2833 UINT _nxe_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index)
2834 {
2835
2836 UINT status;
2837
2838
2839 /* Check for invalid pointer input. */
2840 if (dhcpv6_server_ptr == NX_NULL)
2841 {
2842
2843 return NX_PTR_ERROR;
2844 }
2845
2846 /* Check for invalid parameters. */
2847 if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
2848 {
2849 return NX_INVALID_INTERFACE;
2850 }
2851
2852 if (ga_address_index >= NX_MAX_IPV6_ADDRESSES)
2853 {
2854 return NX_NO_INTERFACE_ADDRESS;
2855 }
2856
2857 /* Call the actual service. */
2858 status = _nx_dhcpv6_server_interface_set(dhcpv6_server_ptr, iface_index, ga_address_index);
2859
2860 return status;
2861 }
2862
2863
2864 /**************************************************************************/
2865 /* */
2866 /* FUNCTION RELEASE */
2867 /* */
2868 /* _nx_dhcpv6_server_interface_set PORTABLE C */
2869 /* 6.1 */
2870 /* AUTHOR */
2871 /* */
2872 /* Yuxin Zhou, Microsoft Corporation */
2873 /* */
2874 /* DESCRIPTION */
2875 /* */
2876 /* This function sets the physical network interface for DHCPv6 */
2877 /* communications and the address index of the IP instance for the */
2878 /* primary global address on that interface. */
2879 /* */
2880 /* INPUT */
2881 /* */
2882 /* dhcpv6_server_ptr Pointer to the DHCPV6 Server */
2883 /* iface_index Physical interface index for */
2884 /* DHCP communication */
2885 /* ga_address_index Global address index on DHCPv6*/
2886 /* interface */
2887 /* */
2888 /* OUTPUT */
2889 /* */
2890 /* NX_SUCCESS Indexes successfully set */
2891 /* */
2892 /* CALLS */
2893 /* */
2894 /* None */
2895 /* */
2896 /* CALLED BY */
2897 /* */
2898 /* */
2899 /* RELEASE HISTORY */
2900 /* */
2901 /* DATE NAME DESCRIPTION */
2902 /* */
2903 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2904 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2905 /* resulting in version 6.1 */
2906 /* */
2907 /**************************************************************************/
_nx_dhcpv6_server_interface_set(NX_DHCPV6_SERVER * dhcpv6_server_ptr,UINT iface_index,UINT ga_address_index)2908 UINT _nx_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index)
2909 {
2910
2911 dhcpv6_server_ptr -> nx_dhcpv6_server_interface_index = iface_index;
2912 dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index = ga_address_index;
2913 return NX_SUCCESS;
2914 }
2915
2916
2917 /**************************************************************************/
2918 /* */
2919 /* FUNCTION RELEASE */
2920 /* */
2921 /* _nx_dhcpv6_server_lease_timeout_entry PORTABLE C */
2922 /* 6.1 */
2923 /* AUTHOR */
2924 /* */
2925 /* Yuxin Zhou, Microsoft Corporation */
2926 /* */
2927 /* DESCRIPTION */
2928 /* */
2929 /* This function is scheduled by the ThreadX scheduler on a user */
2930 /* configurable time interval. It sets a flag for the DHCPv6 server */
2931 /* thread task to check the lease expiration on its leased IP address. */
2932 /* */
2933 /* INPUT */
2934 /* */
2935 /* dhcpv6_server_ptr_value Pointer to the DHCPV6 Server */
2936 /* */
2937 /* OUTPUT */
2938 /* */
2939 /* None */
2940 /* */
2941 /* CALLS */
2942 /* */
2943 /* tx_event_flags_set Adds a periodic event to the */
2944 /* ThreadX event queue */
2945 /* CALLED BY */
2946 /* */
2947 /* */
2948 /* RELEASE HISTORY */
2949 /* */
2950 /* DATE NAME DESCRIPTION */
2951 /* */
2952 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2953 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2954 /* resulting in version 6.1 */
2955 /* */
2956 /**************************************************************************/
_nx_dhcpv6_server_lease_timeout_entry(ULONG dhcpv6_server_ptr_value)2957 VOID _nx_dhcpv6_server_lease_timeout_entry(ULONG dhcpv6_server_ptr_value)
2958 {
2959
2960 NX_DHCPV6_SERVER *dhcpv6_server_ptr;
2961
2962
2963 /* Setup DHCPv6 Server pointer. */
2964 NX_TIMER_EXTENSION_PTR_GET(dhcpv6_server_ptr, NX_DHCPV6_SERVER, dhcpv6_server_ptr_value)
2965
2966 /* Signal the DHCPv6 Server it is time to do check the lease time remaining on
2967 clients it has leased IP addresses to. */
2968 tx_event_flags_set(&(dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events), NX_DHCPV6_IP_LEASE_CHECK_PERIODIC_EVENT, TX_OR);
2969
2970 return;
2971 }
2972
2973
2974 /**************************************************************************/
2975 /* */
2976 /* FUNCTION RELEASE */
2977 /* */
2978 /* _nxe_dhcpv6_server_resume PORTABLE C */
2979 /* 6.1 */
2980 /* AUTHOR */
2981 /* */
2982 /* Yuxin Zhou, Microsoft Corporation */
2983 /* */
2984 /* DESCRIPTION */
2985 /* */
2986 /* This function performs error checking on the resume NetX DHCPv6 */
2987 /* server task service. */
2988 /* */
2989 /* INPUT */
2990 /* */
2991 /* dhcpv6_server_ptr Pointer to DHCPV6 Server */
2992 /* */
2993 /* OUTPUT */
2994 /* */
2995 /* OUTPUT */
2996 /* */
2997 /* status Completion status */
2998 /* NX_PTR_ERROR Invalid pointer input */
2999 /* */
3000 /* CALLS */
3001 /* */
3002 /* _nx_dhcpv6_server_resume Actual DHCPV6 resume function */
3003 /* */
3004 /* CALLED BY */
3005 /* */
3006 /* Application Code */
3007 /* */
3008 /* RELEASE HISTORY */
3009 /* */
3010 /* DATE NAME DESCRIPTION */
3011 /* */
3012 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3013 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3014 /* resulting in version 6.1 */
3015 /* */
3016 /**************************************************************************/
_nxe_dhcpv6_server_resume(NX_DHCPV6_SERVER * dhcpv6_server_ptr)3017 UINT _nxe_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
3018 {
3019
3020 UINT status;
3021
3022
3023 /* Check for invalid input pointer. */
3024 if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID))
3025 return(NX_PTR_ERROR);
3026
3027 /* Check for appropriate caller. */
3028 NX_THREADS_ONLY_CALLER_CHECKING
3029
3030 /* Call actual DHCPV6 stop service. */
3031 status = _nx_dhcpv6_server_resume(dhcpv6_server_ptr);
3032
3033 /* Return status. */
3034 return(status);
3035 }
3036
3037
3038 /**************************************************************************/
3039 /* */
3040 /* FUNCTION RELEASE */
3041 /* */
3042 /* _nx_dhcpv6_server_resume PORTABLE C */
3043 /* 6.1 */
3044 /* AUTHOR */
3045 /* */
3046 /* Yuxin Zhou, Microsoft Corporation */
3047 /* */
3048 /* DESCRIPTION */
3049 /* */
3050 /* This function resumes DHCPV6 processing thread, activates the */
3051 /* timers, and sets the running status of the DHCPv6 Server back to */
3052 /* running. */
3053 /* */
3054 /* INPUT */
3055 /* */
3056 /* dhcpv6_server_ptr Pointer to DHCPV6 server */
3057 /* */
3058 /* OUTPUT */
3059 /* */
3060 /* status Actual completion status */
3061 /* NX_SUCCESS Successful completion status */
3062 /* NX_DHCPV6_ALREADY_STARTED DHPCv6 Server already running */
3063 /* */
3064 /* CALLS */
3065 /* */
3066 /* tx_thread_resume Resumes DHCPV6 thread task */
3067 /* tx_timer_activate Activates DHCPv6 timer */
3068 /* */
3069 /* CALLED BY */
3070 /* */
3071 /* Application Code */
3072 /* */
3073 /* RELEASE HISTORY */
3074 /* */
3075 /* DATE NAME DESCRIPTION */
3076 /* */
3077 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3078 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3079 /* resulting in version 6.1 */
3080 /* */
3081 /**************************************************************************/
_nx_dhcpv6_server_resume(NX_DHCPV6_SERVER * dhcpv6_server_ptr)3082 UINT _nx_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
3083 {
3084
3085 UINT status;
3086
3087
3088 /* Is the DHCPv6 Client already running? */
3089 if (dhcpv6_server_ptr -> nx_dhcpv6_server_running)
3090 {
3091
3092 /* Return a (benign) error status. */
3093 return NX_DHCPV6_ALREADY_STARTED;
3094 }
3095
3096 /* Set the DHCPV6 running flag to indicate DHCPV6 is running. */
3097 dhcpv6_server_ptr -> nx_dhcpv6_server_running = NX_TRUE;
3098
3099 /* Start the lease timer. */
3100 status = tx_timer_activate(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer));
3101
3102 /* Check for invalid activate status. */
3103 if (status != TX_SUCCESS)
3104 {
3105
3106 /* Return error status. */
3107 return status;
3108 }
3109
3110 /* Start the session timer. */
3111 status = tx_timer_activate(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer));
3112
3113 /* Check for invalid activate status. */
3114 if (status != TX_SUCCESS)
3115 {
3116
3117 /* Return error status. */
3118 return status;
3119 }
3120
3121 /* Resume the Server thread as well. */
3122 status = tx_thread_resume(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread));
3123
3124 /* Check for invalid resume status. */
3125 if (status != TX_SUCCESS && status != TX_SUSPEND_LIFTED)
3126 {
3127
3128 /* Return threadx error status. */
3129 return status;
3130 }
3131 /* Return completion status. */
3132 return(NX_SUCCESS);
3133 }
3134
3135
3136 /**************************************************************************/
3137 /* */
3138 /* FUNCTION RELEASE */
3139 /* */
3140 /* _nx_dhcpv6_server_session_timeout_entry PORTABLE C */
3141 /* 6.1 */
3142 /* AUTHOR */
3143 /* */
3144 /* Yuxin Zhou, Microsoft Corporation */
3145 /* */
3146 /* DESCRIPTION */
3147 /* */
3148 /* This function is scheduled by the ThreadX scheduler on a user */
3149 /* configurable time interval. It sets a flag which the DHCPv6 server */
3150 /* thread task updates all active client session times and checks if */
3151 /* any have exceeded the session timeout without sending a response */
3152 /* back to the server. */
3153 /* */
3154 /* INPUT */
3155 /* */
3156 /* dhcpv6_server_ptr_value Pointer to the DHCPV6 server */
3157 /* */
3158 /* OUTPUT */
3159 /* */
3160 /* None */
3161 /* */
3162 /* CALLS */
3163 /* */
3164 /* tx_event_flags_set Adds a periodic event to the */
3165 /* ThreadX event queue */
3166 /* CALLED BY */
3167 /* */
3168 /* */
3169 /* RELEASE HISTORY */
3170 /* */
3171 /* DATE NAME DESCRIPTION */
3172 /* */
3173 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3174 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3175 /* resulting in version 6.1 */
3176 /* */
3177 /**************************************************************************/
_nx_dhcpv6_server_session_timeout_entry(ULONG dhcpv6_server_ptr_value)3178 VOID _nx_dhcpv6_server_session_timeout_entry(ULONG dhcpv6_server_ptr_value)
3179 {
3180
3181 NX_DHCPV6_SERVER *dhcpv6_server_ptr;
3182
3183
3184 /* Setup DHCPv6 Server pointer. */
3185 NX_TIMER_EXTENSION_PTR_GET(dhcpv6_server_ptr, NX_DHCPV6_SERVER, dhcpv6_server_ptr_value)
3186
3187 /* Signal the DHCPv6 server it's time to do more session time keeping! */
3188 tx_event_flags_set(&(dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events), NX_DHCPV6_CHECK_SESSION_PERIODIC_EVENT, TX_OR);
3189
3190 return;
3191 }
3192
3193
3194 /**************************************************************************/
3195 /* */
3196 /* FUNCTION RELEASE */
3197 /* */
3198 /* _nxe_dhcpv6_server_start PORTABLE C */
3199 /* 6.1 */
3200 /* AUTHOR */
3201 /* */
3202 /* Yuxin Zhou, Microsoft Corporation */
3203 /* */
3204 /* DESCRIPTION */
3205 /* */
3206 /* This function performs error checking on the NetX start the dhcpv6 */
3207 /* client service. */
3208 /* */
3209 /* INPUT */
3210 /* */
3211 /* dhcpv6_server_ptr Pointer to DHCPV6 Server */
3212 /* */
3213 /* OUTPUT */
3214 /* */
3215 /* status Completion status */
3216 /* NX_PTR_ERROR Invalid pointer input */
3217 /* */
3218 /* */
3219 /* CALLS */
3220 /* */
3221 /* _nx_dhcpv6_server_start Actual DHCPV6 start function */
3222 /* */
3223 /* CALLED BY */
3224 /* */
3225 /* Application Code */
3226 /* */
3227 /* RELEASE HISTORY */
3228 /* */
3229 /* DATE NAME DESCRIPTION */
3230 /* */
3231 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3232 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3233 /* resulting in version 6.1 */
3234 /* */
3235 /**************************************************************************/
_nxe_dhcpv6_server_start(NX_DHCPV6_SERVER * dhcpv6_server_ptr)3236 UINT _nxe_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
3237 {
3238
3239 UINT status;
3240
3241
3242 /* Check for invalid input pointer. */
3243 if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID))
3244 return(NX_PTR_ERROR);
3245
3246 /* Check for appropriate caller. */
3247 NX_THREADS_ONLY_CALLER_CHECKING
3248
3249 /* Call actual DHCPV6 start service. */
3250 status = _nx_dhcpv6_server_start(dhcpv6_server_ptr);
3251
3252 /* Return status. */
3253 return(status);
3254 }
3255
3256
3257 /**************************************************************************/
3258 /* */
3259 /* FUNCTION RELEASE */
3260 /* */
3261 /* _nx_dhcpv6_server_start PORTABLE C */
3262 /* 6.1 */
3263 /* AUTHOR */
3264 /* */
3265 /* Yuxin Zhou, Microsoft Corporation */
3266 /* */
3267 /* DESCRIPTION */
3268 /* */
3269 /* This function starts the DHCPV6 processing thread and prepares the */
3270 /* DHCPv6 Server to receive DHCPv6 client requests. */
3271 /* */
3272 /* INPUT */
3273 /* */
3274 /* dhcpv6_server_ptr Pointer to DHCPV6 Server */
3275 /* */
3276 /* OUTPUT */
3277 /* */
3278 /* status Completion status */
3279 /* NX_DHCPV6_ALREADY_STARTED DHCPv6 server already started */
3280 /* NX_DHCPV6_MISSING_REQUIRED_OPTIONS Server missing required options */
3281 /* NX_DHCPV6_NO_ASSIGNABLE_ADDRESSES No addresses available to assign*/
3282 /* */
3283 /* CALLS */
3284 /* */
3285 /* nxd_ipv6_linklocal_address_set Obtain MAC address for DUID */
3286 /* nx_udp_socket_create Create the Server UDP socket */
3287 /* nx_udp_socket_bind Bind the Server socket */
3288 /* nx_udp_socket_unbind Unbind the Server socket */
3289 /* tx_timer_activate Activate Server lease timer */
3290 /* tx_timer_deactivate Deactivate Server lease timer */
3291 /* tx_thread_resume Resume Server thread task */
3292 /* */
3293 /* CALLED BY */
3294 /* */
3295 /* Application Code */
3296 /* */
3297 /* RELEASE HISTORY */
3298 /* */
3299 /* DATE NAME DESCRIPTION */
3300 /* */
3301 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3302 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3303 /* resulting in version 6.1 */
3304 /* */
3305 /**************************************************************************/
_nx_dhcpv6_server_start(NX_DHCPV6_SERVER * dhcpv6_server_ptr)3306 UINT _nx_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
3307 {
3308
3309 UINT status;
3310 #ifdef NETXDUO_MULTI_HOME
3311 UINT if_index;
3312 #endif
3313
3314
3315 /* Determine if the DHCPV6 server has already started. */
3316 if (dhcpv6_server_ptr -> nx_dhcpv6_server_running)
3317 {
3318
3319 /* Yes, it has. */
3320 return(NX_DHCPV6_ALREADY_STARTED);
3321 }
3322
3323 /* Check if the server has assignable addresses. */
3324 if (dhcpv6_server_ptr -> nx_dhcpv6_assignable_addresses == 0)
3325 {
3326 return NX_DHCPV6_NO_ASSIGNABLE_ADDRESSES;
3327 }
3328
3329 /* Check that the global address is valid. */
3330 if (dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index >= NX_MAX_IPV6_ADDRESSES)
3331 {
3332 return NX_DHCPV6_INVALID_GLOBAL_INDEX;
3333 }
3334
3335 /* Create the Socket and check the status */
3336 status = nx_udp_socket_create(dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr,
3337 &(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), (CHAR *)"NetX DHCPV6 Server",
3338 NX_DHCPV6_TYPE_OF_SERVICE, NX_DHCPV6_FRAGMENT_OPTION,
3339 NX_DHCPV6_TIME_TO_LIVE, NX_DHCPV6_QUEUE_DEPTH);
3340
3341 /* Was the socket creation successful? */
3342 if (status != NX_SUCCESS)
3343 {
3344
3345 /* No, return error status. */
3346 return status;
3347 }
3348
3349 /* Save the DHCP instance pointer in the socket. */
3350 dhcpv6_server_ptr -> nx_dhcpv6_server_socket.nx_udp_socket_reserved_ptr = (void *) dhcpv6_server_ptr;
3351
3352 /* Set the DHCPv6 request handler for packets received on the DHCPv6 server socket. */
3353 status = nx_udp_socket_receive_notify(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), _nx_dhcpv6_server_socket_receive_notify);
3354
3355 /* Was the socket receive_notify set successful? */
3356 if (status != NX_SUCCESS)
3357 {
3358
3359 /* No, return error status. */
3360 return status;
3361 }
3362
3363 /* Check if the host application has created or retrieved a previously created server DUID. */
3364 if (dhcpv6_server_ptr -> nx_dhcpv6_server_duid.nx_duid_type == 0)
3365 {
3366
3367 /* No valid server DUID detected. Server cannot run yet!*/
3368 return NX_DHCPV6_NO_SERVER_DUID;
3369 }
3370
3371 /* Bind the UDP socket to the DHCPV6 Server port. */
3372 status = nx_udp_socket_bind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), NX_DHCPV6_SERVER_UDP_PORT, TX_WAIT_FOREVER);
3373
3374 /* Check status. */
3375 if (status != NX_SUCCESS)
3376 {
3377
3378 /* Delete the UDP socket. */
3379 nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket));
3380
3381 return status;
3382 }
3383
3384 /* Activate the DHCPv6 timers. */
3385 status = tx_timer_activate(&dhcpv6_server_ptr -> nx_dhcpv6_lease_timer);
3386
3387 /* Determine if the timer activate call was successful. */
3388 if ((status != TX_SUCCESS) && (status != TX_ACTIVATE_ERROR))
3389 {
3390
3391 /* No it was not; unbind the DHCPV6 socket. */
3392 nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket));
3393
3394 /* Delete the UDP socket. */
3395 nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket));
3396
3397 /* Return the error status. */
3398 return status;
3399 }
3400
3401 /* Start the session timer. */
3402 status = tx_timer_activate(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer));
3403
3404 /* Check for invalid activate status. */
3405 if ((status != TX_SUCCESS) && (status != TX_ACTIVATE_ERROR))
3406 {
3407
3408 /* No it was not; unbind the DHCPV6 socket. */
3409 nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket));
3410
3411 /* Delete the UDP socket. */
3412 nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket));
3413
3414 /* Return error status. */
3415 return status;
3416 }
3417
3418 /* Ready to resume the DHCPV6 server thread. */
3419 status = tx_thread_resume(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread));
3420
3421 /* Determine if the resume was successful. */
3422 if (status != NX_SUCCESS)
3423 {
3424
3425 /* Deactivate the timer. */
3426 tx_timer_deactivate(&dhcpv6_server_ptr -> nx_dhcpv6_lease_timer);
3427
3428 /* Unbind the DHCPV6 socket. */
3429 nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket));
3430
3431 /* Delete the UDP socket. */
3432 nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket));
3433
3434 return status;
3435 }
3436
3437 /* Set the DHCPV6 started flag to indicate the DHCPV6 server is now running. */
3438 dhcpv6_server_ptr -> nx_dhcpv6_server_running = NX_TRUE;
3439
3440 /* Return completion status. */
3441 return(status);
3442 }
3443
3444 /**************************************************************************/
3445 /* */
3446 /* FUNCTION RELEASE */
3447 /* */
3448 /* _nx_dhcpv6_server_socket_receive_notify PORTABLE C */
3449 /* 6.1 */
3450 /* AUTHOR */
3451 /* */
3452 /* Yuxin Zhou, Microsoft Corporation */
3453 /* */
3454 /* DESCRIPTION */
3455 /* */
3456 /* This function is notified by NetX Duo when a packet arrives in the */
3457 /* server socket. It sets a flag which the DHCPv6 server thread */
3458 /* detect so it will know to process the incoming packet . */
3459 /* */
3460 /* INPUT */
3461 /* */
3462 /* socket_ptr Pointer to Server Socket */
3463 /* */
3464 /* OUTPUT */
3465 /* */
3466 /* None */
3467 /* */
3468 /* CALLS */
3469 /* */
3470 /* None */
3471 /* */
3472 /* CALLED BY */
3473 /* */
3474 /* Threads */
3475 /* */
3476 /* RELEASE HISTORY */
3477 /* */
3478 /* DATE NAME DESCRIPTION */
3479 /* */
3480 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3481 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3482 /* resulting in version 6.1 */
3483 /* */
3484 /**************************************************************************/
_nx_dhcpv6_server_socket_receive_notify(NX_UDP_SOCKET * socket_ptr)3485 VOID _nx_dhcpv6_server_socket_receive_notify(NX_UDP_SOCKET *socket_ptr)
3486 {
3487
3488 NX_DHCPV6_SERVER *dhcpv6_server_ptr;
3489
3490
3491 /* Get a pointer to the DHCPv6 server. */
3492 dhcpv6_server_ptr = (NX_DHCPV6_SERVER *) socket_ptr -> nx_udp_socket_reserved_ptr;
3493
3494 /* Signal the DHCPv6 Server it has a UDP packet on its socket receive queue. */
3495 tx_event_flags_set(&(dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events), NX_DHCPV6_SERVER_RECEIVE_EVENT, TX_OR);
3496
3497 return;
3498 }
3499
3500
3501 /**************************************************************************/
3502 /* */
3503 /* FUNCTION RELEASE */
3504 /* */
3505 /* _nxe_dhcpv6_server_suspend PORTABLE C */
3506 /* 6.1 */
3507 /* AUTHOR */
3508 /* */
3509 /* Yuxin Zhou, Microsoft Corporation */
3510 /* */
3511 /* DESCRIPTION */
3512 /* */
3513 /* This function performs error checking on the suspend NetX DHCPv6 */
3514 /* Server task service. */
3515 /* */
3516 /* INPUT */
3517 /* */
3518 /* dhcpv6_server_ptr Pointer to DHCPV6 server */
3519 /* */
3520 /* OUTPUT */
3521 /* */
3522 /* status Completion status */
3523 /* NX_PTR_ERROR Invalid pointer input */
3524 /* */
3525 /* CALLS */
3526 /* */
3527 /* _nx_dhcpv6_server_suspend Actual DHCPV6 suspend function */
3528 /* */
3529 /* CALLED BY */
3530 /* */
3531 /* Application Code */
3532 /* */
3533 /* RELEASE HISTORY */
3534 /* */
3535 /* DATE NAME DESCRIPTION */
3536 /* */
3537 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3538 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3539 /* resulting in version 6.1 */
3540 /* */
3541 /**************************************************************************/
_nxe_dhcpv6_server_suspend(NX_DHCPV6_SERVER * dhcpv6_server_ptr)3542 UINT _nxe_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
3543 {
3544
3545 UINT status;
3546
3547
3548 /* Check for invalid input pointer. */
3549 if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID))
3550 return(NX_PTR_ERROR);
3551
3552 /* Check for appropriate caller. */
3553 NX_THREADS_ONLY_CALLER_CHECKING
3554
3555 /* Call actual DHCPV6 stop service. */
3556 status = _nx_dhcpv6_server_suspend(dhcpv6_server_ptr);
3557
3558 /* Return status. */
3559 return(status);
3560 }
3561
3562
3563 /**************************************************************************/
3564 /* */
3565 /* FUNCTION RELEASE */
3566 /* */
3567 /* _nx_dhcpv6_server_suspend PORTABLE C */
3568 /* 6.1 */
3569 /* AUTHOR */
3570 /* */
3571 /* Yuxin Zhou, Microsoft Corporation */
3572 /* */
3573 /* DESCRIPTION */
3574 /* */
3575 /* This function suspends DHCPV6 processing thread, deactivates the */
3576 /* timers, and sets the running status of the DHCPv6 Server to not */
3577 /* running. */
3578 /* */
3579 /* INPUT */
3580 /* */
3581 /* dhcpv6_server_ptr Pointer to DHCPV6 Server */
3582 /* */
3583 /* OUTPUT */
3584 /* */
3585 /* NX_SUCCESS Successful completion status */
3586 /* NX_DHCPV6_NOT_STARTED Task not running; can't be */
3587 /* suspended */
3588 /* */
3589 /* CALLS */
3590 /* */
3591 /* tx_thread_suspend Suspend DHCPV6 thread task */
3592 /* tx_timer_deactivate Deactivate timer */
3593 /* */
3594 /* CALLED BY */
3595 /* */
3596 /* Application Code */
3597 /* */
3598 /* RELEASE HISTORY */
3599 /* */
3600 /* DATE NAME DESCRIPTION */
3601 /* */
3602 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3603 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3604 /* resulting in version 6.1 */
3605 /* */
3606 /**************************************************************************/
_nx_dhcpv6_server_suspend(NX_DHCPV6_SERVER * dhcpv6_server_ptr)3607 UINT _nx_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
3608 {
3609
3610
3611 /* Determine if the DHCPV6 server thread is running. */
3612 if (!dhcpv6_server_ptr -> nx_dhcpv6_server_running)
3613 {
3614
3615 /* DHCPV6 has not been started so we cannot 'suspend' it. */
3616 return(NX_DHCPV6_NOT_STARTED);
3617 }
3618
3619 /* Clear the DHCPV6 running flag to indicate DHCPV6 is not running. */
3620 dhcpv6_server_ptr -> nx_dhcpv6_server_running = NX_FALSE;
3621
3622 /* Stop the timer. */
3623 tx_timer_deactivate(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer));
3624
3625 /* Suspend the Server thread as well. */
3626 tx_thread_suspend(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread));
3627
3628 /* Return completion status. */
3629 return(NX_SUCCESS);
3630 }
3631
3632
3633 /**************************************************************************/
3634 /* */
3635 /* FUNCTION RELEASE */
3636 /* */
3637 /* _nx_dhcpv6_server_thread_entry PORTABLE C */
3638 /* 6.1 */
3639 /* AUTHOR */
3640 /* */
3641 /* Yuxin Zhou, Microsoft Corporation */
3642 /* */
3643 /* DESCRIPTION */
3644 /* */
3645 /* This function is the background processing thread for the DHCPV6 */
3646 /* Client. It waits to be notified by ThreadX event flags when to */
3647 /* perform certain actions. These include updating the time remaining */
3648 /* on the Client IP address lease time, and maintaining the duration of*/
3649 /* the current Client Server session (if Client has made a request). */
3650 /* It will terminate if a host application handler is called and */
3651 /* indicates the Client should abort. */
3652 /* */
3653 /* INPUT */
3654 /* */
3655 /* info Pointer to DHCPV6 Client instance*/
3656 /* */
3657 /* OUTPUT */
3658 /* */
3659 /* None */
3660 /* */
3661 /* CALLS */
3662 /* */
3663 /* tx_event_flags_get Receive notice of event flags set */
3664 /* tx_mutex_get Obtain lock on Client resource */
3665 /* tx_mutex_put Release lock on Client resource */
3666 /* nx_dhcpv6_deprecated_IP_address_handler */
3667 /* Callback function for handling an */
3668 /* IP address at the end of its */
3669 /* preferred life time */
3670 /* nx_dhcpv6_expired_IP_address_handler */
3671 /* Callback function for handling an */
3672 /* IP address at the end of its */
3673 /* valid life time */
3674 /* _nx_dhcpv6_request_renew Initiate the RENEW request */
3675 /* _nx_dhcpv6_request_rebind Initiate the REBIND request */
3676 /* */
3677 /* CALLED BY */
3678 /* */
3679 /* ThreadX */
3680 /* */
3681 /* RELEASE HISTORY */
3682 /* */
3683 /* DATE NAME DESCRIPTION */
3684 /* */
3685 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3686 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3687 /* resulting in version 6.1 */
3688 /* */
3689 /**************************************************************************/
_nx_dhcpv6_server_thread_entry(ULONG info)3690 VOID _nx_dhcpv6_server_thread_entry(ULONG info)
3691 {
3692
3693 UINT i;
3694 NX_DHCPV6_SERVER *dhcpv6_server_ptr;
3695 NX_DHCPV6_CLIENT *dhcpv6_client_ptr;
3696 ULONG dhcpv6_events;
3697 NXD_ADDRESS client_address;
3698
3699
3700 /* Setup the DHCPV6 server pointer. */
3701 NX_THREAD_EXTENSION_PTR_GET(dhcpv6_server_ptr, NX_DHCPV6_SERVER, info)
3702
3703 /* Continue processing periodic tasks till this internal flag is cleared. */
3704 while (1)
3705 {
3706
3707
3708 /* Pick up IP event flags. */
3709 tx_event_flags_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events, NX_DHCPV6_ALL_EVENTS,
3710 TX_OR_CLEAR, &dhcpv6_events, TX_WAIT_FOREVER);
3711
3712 if (dhcpv6_events & NX_DHCPV6_SERVER_RECEIVE_EVENT)
3713 {
3714
3715 /* Listen for new Client DHCP service request e.g. DISCOVERY messages. */
3716 _nx_dhcpv6_listen_for_messages(dhcpv6_server_ptr);
3717 }
3718
3719 if (dhcpv6_events & NX_DHCPV6_CHECK_SESSION_PERIODIC_EVENT)
3720 {
3721 /* Check the active clients whose sessions that have timed out. */
3722 for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++)
3723 {
3724
3725 /* Set a local pointer for convenience. */
3726 dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i];
3727
3728 tx_mutex_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex, NX_WAIT_FOREVER);
3729
3730 /* Is this client in session with the server? */
3731 if (dhcpv6_client_ptr -> nx_dhcpv6_client_session_time)
3732 {
3733
3734 /* Update the Client session time. */
3735 dhcpv6_client_ptr -> nx_dhcpv6_client_session_time += NX_DHCPV6_SESSION_TIMER_INTERVAL;
3736
3737 if (dhcpv6_client_ptr -> nx_dhcpv6_client_session_time >= NX_DHCPV6_SESSION_TIMEOUT)
3738 {
3739
3740 /* The session has timed out without a response from the Client. Invalidate
3741 the client entry. */
3742
3743 /* First get the assigned address. */
3744 COPY_IPV6_ADDRESS(&dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0],
3745 &client_address.nxd_ip_address.v6[0]);
3746
3747 /* Clear the client record. */
3748 _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr);
3749 }
3750 }
3751
3752 tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex);
3753 }
3754 }
3755
3756 /* Check for a periodic DHCP server task. */
3757 if (dhcpv6_events & NX_DHCPV6_IP_LEASE_CHECK_PERIODIC_EVENT)
3758 {
3759
3760 /* Check the active clients for the time remaining in their leased IP address. */
3761 for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++)
3762 {
3763
3764 /* Set a local pointer for convenience. */
3765 dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i];
3766
3767 tx_mutex_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex, NX_WAIT_FOREVER);
3768
3769 /* Skip those clients who do not have a lease assigned yet. */
3770 if (dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued == 0)
3771 {
3772
3773 tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex);
3774
3775 continue;
3776 }
3777
3778 /* Update the time accrued on the client's current IP address lease. */
3779 dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued += NX_DHCPV6_IP_LEASE_TIMER_INTERVAL;
3780
3781 /* Has this address become obsolete? */
3782 if (dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued >= dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime)
3783 {
3784
3785 tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex);
3786
3787 /* Clear the client record. */
3788 _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr);
3789 }
3790 else if (dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued >=
3791 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime)
3792 {
3793
3794 /* Address is deprecated! Client *should* not use it but no action taken by the server yet. */
3795 }
3796
3797 tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex);
3798 }
3799 }
3800
3801 /* Relinquish control before another cycle.*/
3802 tx_thread_sleep(1);
3803 }
3804 }
3805
3806
3807 /**************************************************************************/
3808 /* */
3809 /* FUNCTION RELEASE */
3810 /* */
3811 /* _nx_dhcpv6_server_extract_packet_information PORTABLE C */
3812 /* 6.3.0 */
3813 /* AUTHOR */
3814 /* */
3815 /* Yuxin Zhou, Microsoft Corporation */
3816 /* */
3817 /* DESCRIPTION */
3818 /* */
3819 /* This function extracts data from DHCPv6 Client request packets. A */
3820 /* request is checked for valid message type and required DHCPv6 data. */
3821 /* A client record is created if one does not exist for the client and */
3822 /* the data updated into it. */
3823 /* */
3824 /* INPUT */
3825 /* */
3826 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
3827 /* dhcpv6_client_ptr Pointer to DHCPv6 client */
3828 /* packet_ptr Pointer to received packet */
3829 /* iface_index Interface packet received on */
3830 /* */
3831 /* OUTPUT */
3832 /* */
3833 /* status Actual completion status */
3834 /* NX_SUCCESS Successful completion status */
3835 /* NX_DHCPV6_ILLEGAL_MESSAGE_TYPE Packet message type illegal */
3836 /* NX_DHCPV6_BAD_TRANSACTION_ID Message ID fails to match up */
3837 /* NX_DHCPV6_PROCESSING_ERROR Packet length is different than */
3838 /* expected */
3839 /* NX_DHCPV6_UNKNOWN_OPTION Unknown option in message */
3840 /* NX_DHCPV6_INVALID_HW_ADDRESS Missing or invalid MAC address */
3841 /* */
3842 /* CALLS */
3843 /* */
3844 /* _nx_dhcpv6_server_utility_get_data Extract data from reply packet */
3845 /* _nx_dhcpv6_server_utility_get_block_option_length */
3846 /* Extract option header data */
3847 /* _nx_dhcpv6_process_duid Extract DUID from Client message*/
3848 /* _nx_dhcpv6_process_DNS_server Extract DNS server from message */
3849 /* memcpy Copies specified area of memory */
3850 /* */
3851 /* CALLED BY */
3852 /* */
3853 /* _nx_dhcpv6_listen_for_messages Waits to receive client message*/
3854 /* */
3855 /* RELEASE HISTORY */
3856 /* */
3857 /* DATE NAME DESCRIPTION */
3858 /* */
3859 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3860 /* 09-30-2020 Yuxin Zhou Modified comment(s), improved */
3861 /* packet length verification, */
3862 /* verified memcpy use cases, */
3863 /* resulting in version 6.1 */
3864 /* 10-31-2023 Haiqing Zhao Modified comment(s), and */
3865 /* updated client record on */
3866 /* each message, */
3867 /* resulting in version 6.3.0 */
3868 /* */
3869 /**************************************************************************/
_nx_dhcpv6_server_extract_packet_information(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_CLIENT ** dhcpv6_client_ptr,NX_PACKET * packet_ptr,UINT iface_index,NXD_ADDRESS source_address,NXD_ADDRESS destination_address)3870 UINT _nx_dhcpv6_server_extract_packet_information(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT **dhcpv6_client_ptr, NX_PACKET *packet_ptr,
3871 UINT iface_index, NXD_ADDRESS source_address, NXD_ADDRESS destination_address)
3872 {
3873
3874 UINT status;
3875 UINT add_on;
3876 UINT record_index;
3877 ULONG option_code;
3878 ULONG option_length;
3879 UCHAR *buffer_ptr;
3880 UINT index;
3881 ULONG returned_xid;
3882 NX_DHCPV6_SVR_DUID client_duid, server_duid;
3883 UINT client_duid_received;
3884 UINT server_duid_received;
3885 NX_DHCPV6_CLIENT temp_client_rec;
3886 ULONG received_message_type;
3887 UINT matching;
3888
3889 NX_PARAMETER_NOT_USED(iface_index);
3890
3891 *dhcpv6_client_ptr = NX_NULL;
3892
3893 /* Create a scratch record for this client so we can qualify it before adding it to the server table. */
3894 memset(&temp_client_rec, 0, sizeof(NX_DHCPV6_CLIENT));
3895
3896 /* Initialize the record with the DHCPv6 Client ID. */
3897 temp_client_rec.nx_dhcpv6_id = NX_DHCPV6_CLIENT_ID;
3898
3899 /* Assume the Client is not bound to an IP address yet. */
3900 temp_client_rec.nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND;
3901
3902 /* Check packet for message type and transaction ID. */
3903 if (packet_ptr -> nx_packet_length < 4)
3904 {
3905
3906 /* Reported length of the packet may be incorrect. */
3907 return NX_DHCPV6_PROCESSING_ERROR;
3908 }
3909
3910 /* Set a pointer to the start of DHCPv6 data. */
3911 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
3912
3913 /* Initialize local variables. */
3914 index = 0;
3915 client_duid_received = NX_FALSE;
3916 server_duid_received = NX_FALSE;
3917
3918 /* Extract the message type which should be the first byte. */
3919 _nx_dhcpv6_server_utility_get_data(buffer_ptr, 1, &received_message_type);
3920
3921 /* Check for an illegal message type. */
3922 if ((received_message_type == NX_DHCPV6_MESSAGE_TYPE_ADVERTISE) ||
3923 (received_message_type == NX_DHCPV6_MESSAGE_TYPE_REPLY) ||
3924 (received_message_type == NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE) ||
3925 (received_message_type > NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST))
3926 {
3927
3928 /* These should only be sent to DHCPv6 clients! The Inform Request is actually
3929 legal to receive but should NOT be used to add clients to the server table. */
3930 return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE;
3931 }
3932
3933 /* Copy the source address to the Client record. */
3934 COPY_IPV6_ADDRESS(&source_address.nxd_ip_address.v6[0], &temp_client_rec.nx_dhcp_source_ip_address.nxd_ip_address.v6[0]);
3935 temp_client_rec.nx_dhcp_source_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
3936
3937 /* Copy the destination address to the Client record. */
3938 COPY_IPV6_ADDRESS(&destination_address.nxd_ip_address.v6[0], &temp_client_rec.nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]);
3939 temp_client_rec.nx_dhcp_destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
3940
3941 /* Advance to the data pointer. */
3942 buffer_ptr++;
3943
3944 /* Parse the transaction ID. */
3945 _nx_dhcpv6_server_utility_get_data(buffer_ptr, 3, &returned_xid);
3946
3947 temp_client_rec.nx_dhcpv6_message_type = received_message_type;
3948
3949 /* Set the message ID. The server will need this to reply to the Client. */
3950 temp_client_rec.nx_dhcpv6_message_xid = returned_xid;
3951
3952 buffer_ptr += 3;
3953
3954 /* Update index for message type and transaction ID. */
3955 index += 4;
3956
3957 /* Now parse all the DHCPv6 option blocks in the packet buffer. */
3958 /* 4 bytes for option code and option length. */
3959 while (index + 4 <= packet_ptr -> nx_packet_length)
3960 {
3961
3962 /* Get the option code and length of data of the current option block. */
3963 status = _nx_dhcpv6_server_utility_get_block_option_length(buffer_ptr, &option_code, &option_length);
3964
3965 /* Check that the block data is valid. */
3966 if (status != NX_SUCCESS)
3967 {
3968
3969 /* No, return the error status. */
3970 return status;
3971 }
3972
3973 /* Keep track of how far into the packet we have parsed. */
3974 index += option_length + 4;
3975
3976 /* This is a double check to verify we haven't gone off the end of the packet buffer. */
3977 if (index > packet_ptr -> nx_packet_length)
3978 {
3979
3980 /* Reported length of the packet may be incorrect. At any rate, we don't know
3981 exactly what the end of the message is, so abort. */
3982 return NX_DHCPV6_PROCESSING_ERROR;
3983 }
3984
3985 /* Update buffer pointer to option data. */
3986 buffer_ptr += 4;
3987
3988 /* Process the option code with an option specific API. */
3989 switch (option_code)
3990 {
3991
3992 /* Note - these 'process' functions will not move the buffer pointer. */
3993
3994 case NX_DHCPV6_OP_DUID_CLIENT:
3995
3996 client_duid.nx_op_code = (USHORT)option_code;
3997 client_duid.nx_option_length = (USHORT)option_length;
3998
3999 status = _nx_dhcpv6_process_duid(&client_duid, option_code, option_length, buffer_ptr);
4000
4001 if (status != NX_SUCCESS)
4002 {
4003
4004 return status;
4005 }
4006
4007 /* Copy to the temporary client record. */
4008 memcpy(&temp_client_rec.nx_dhcpv6_client_duid, &client_duid, sizeof(NX_DHCPV6_SVR_DUID)); /* Use case of memcpy is verified. */
4009
4010 /* Indicate the message contained the required Client DUID. */
4011 client_duid_received = NX_TRUE;
4012
4013 break;
4014
4015 case NX_DHCPV6_OP_DUID_SERVER:
4016
4017 server_duid.nx_op_code = (USHORT)option_code;
4018 server_duid.nx_option_length = (USHORT)option_length;
4019
4020 status = _nx_dhcpv6_process_duid(&server_duid, option_code, option_length, buffer_ptr);
4021
4022 if (status != NX_SUCCESS)
4023 {
4024
4025 return status;
4026 }
4027
4028 /* Copy to the temporary client record. */
4029 memcpy(&temp_client_rec.nx_dhcpv6_server_duid, &server_duid, sizeof(NX_DHCPV6_SVR_DUID)); /* Use case of memcpy is verified. */
4030
4031 /* Indicate the message contained the required Server DUID. */
4032 server_duid_received = NX_TRUE;
4033
4034 break;
4035
4036
4037 case NX_DHCPV6_OP_IA_NA:
4038
4039 status = _nx_dhcpv6_server_process_iana(&temp_client_rec, option_code, option_length, buffer_ptr);
4040
4041 if (status != NX_SUCCESS)
4042 {
4043 return status;
4044 }
4045
4046 break;
4047
4048 /* This should not happen. The IA address option must be embedded in the IANA option. */
4049 case NX_DHCPV6_OP_IA_ADDRESS:
4050
4051 /* Don't process an IA address option outside of an address association (IANA). */
4052 status = NX_DHCPV6_IANA_OPTION_MISSING;
4053
4054 break;
4055
4056 case NX_DHCPV6_OP_OPTION_REQUEST:
4057
4058 /* Option request option contains request usually for network configuration parameters
4059 such as the DNS server. */
4060 status = _nx_dhcpv6_process_option_request(&temp_client_rec, option_code, option_length, buffer_ptr);
4061
4062 if (status != NX_SUCCESS)
4063 {
4064
4065 return status;
4066 }
4067
4068 break;
4069
4070 case NX_DHCPV6_OP_ELAPSED_TIME:
4071
4072 /* The elapsed time is time elapsed since the client initiated the IP lease request. */
4073 status = _nx_dhcpv6_process_elapsed_time(&temp_client_rec, option_code, option_length, buffer_ptr);
4074
4075 if (status != NX_SUCCESS)
4076 {
4077
4078 return status;
4079 }
4080
4081 break;
4082
4083
4084 default:
4085 break;
4086 }
4087
4088 /* Check for errors from option block processing. */
4089 if (status != NX_SUCCESS)
4090 {
4091
4092
4093 return status;
4094 }
4095
4096 /* Move to the next top level option. */
4097 buffer_ptr += option_length;
4098 }
4099
4100 /* Check for an improperly formatted packet. */
4101 if (index != packet_ptr -> nx_packet_length)
4102 {
4103
4104 /* If we get here if we are not at the expected end of the buffer. Oops */
4105 return NX_DHCPV6_PROCESSING_ERROR;
4106 }
4107
4108 /* Check if the message is missing the required DUID(s). */
4109 if ((temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) ||
4110 (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND))
4111 {
4112
4113 if (!client_duid_received)
4114 {
4115
4116 return NX_DHCPV6_MESSAGE_DUID_MISSING;
4117 }
4118 }
4119 /* The following message types must include a client and server DUID. */
4120 else if ((temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) ||
4121 (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) ||
4122 (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE))
4123 {
4124
4125 if (!server_duid_received || !client_duid_received)
4126 {
4127
4128 return NX_DHCPV6_MESSAGE_DUID_MISSING;
4129 }
4130 }
4131 /* An inform request only requires a server DUID. */
4132 else if (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)
4133 {
4134
4135 /* The Inform request message should NOT include an IA. */
4136 if (temp_client_rec.nx_dhcpv6_ia.nx_op_code != 0)
4137 {
4138 return NX_DHCPV6_INVALID_IA_DATA;
4139 }
4140 }
4141
4142 /* Validate the client message, and determine how (if) the server should respond to it. */
4143 status = _nx_dhcpv6_validate_client_message(dhcpv6_server_ptr, &temp_client_rec);
4144
4145 /* Check for errors. */
4146 if (status != NX_SUCCESS)
4147 {
4148
4149 /* Return all other errors as completion status. Do not send a message to the client. */
4150 return(status);
4151 }
4152
4153 if (temp_client_rec.nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT)
4154 {
4155
4156 /* Not responding to client. So do not assign an IP address or update
4157 the client record with invalid message. */
4158 return NX_SUCCESS;
4159 }
4160
4161 /* Look up the client record in the server table. If not found, or this is
4162 a new request e.g. a SOLICIT message, create a new client entry in the table and
4163 fill in the extracted information. */
4164 add_on = NX_FALSE;
4165
4166 if ((received_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) ||
4167 (received_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM) ||
4168 (received_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST))
4169 {
4170
4171 /* Check first if the validation process indicates we do not reply to this message. */
4172 if (temp_client_rec.nx_dhcpv6_response_back_from_server != NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT)
4173 {
4174
4175 /* Ok to update or create a new record. */
4176 add_on = NX_TRUE;
4177 }
4178 }
4179
4180 /* Check if the client is already in the server table. */
4181 status = _nx_dhcpv6_find_client_record_by_duid(dhcpv6_server_ptr, &client_duid, &record_index,
4182 add_on, temp_client_rec.nx_dhcpv6_message_xid, &matching);
4183
4184 /* Check for error during search. */
4185 if (status != NX_SUCCESS)
4186 {
4187
4188 return(status);
4189 }
4190
4191 /* Set a local pointer to the client record in the server table. */
4192 *dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[record_index];
4193
4194 /* Was a match was found? */
4195 if (matching)
4196 {
4197
4198 /* This is a different message from the Client. Before updating the record check the client global address
4199 to be the same as what the server assigned or is offering to assign. */
4200 if (!CHECK_IPV6_ADDRESSES_SAME(&temp_client_rec.nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0],
4201 &(*dhcpv6_client_ptr )-> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0]))
4202 {
4203
4204 /* This is a different address. Disregard this message. */
4205 (*dhcpv6_client_ptr) -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4206
4207 return NX_SUCCESS;
4208 }
4209 }
4210
4211 /* Update the client record. */
4212 status = _nx_dhcpv6_update_client_record(dhcpv6_server_ptr, &temp_client_rec, *dhcpv6_client_ptr);
4213
4214 /* Yes we're done with no processing errors detected. */
4215 return NX_SUCCESS;
4216 }
4217
4218
4219 /**************************************************************************/
4220 /* */
4221 /* FUNCTION RELEASE */
4222 /* */
4223 /* _nx_dhcpv6_validate_client_message PORTABLE C */
4224 /* 6.1 */
4225 /* AUTHOR */
4226 /* */
4227 /* Yuxin Zhou, Microsoft Corporation */
4228 /* */
4229 /* DESCRIPTION */
4230 /* */
4231 /* This function validates the client DHCPv6 request, determines if an */
4232 /* IP address need to be assigned, what state the DHCPv6 Client */
4233 /* should be advanced to, and what the server response type should be. */
4234 /* */
4235 /* INPUT */
4236 /* */
4237 /* dhcpv6_server_ptr Pointer to DHCPv6 server */
4238 /* dhcpv6_client_ptr Pointer to DHCPv6 client */
4239 /* */
4240 /* OUTPUT */
4241 /* */
4242 /* NX_SUCCESS Table searched successfully */
4243 /* */
4244 /* CALLS */
4245 /* */
4246 /* _nx_dhcp_update_assignable_ip_address Update IP address status in */
4247 /* the server database */
4248 /* */
4249 /* CALLED BY */
4250 /* */
4251 /* _nx_dhcpv6_listen_for_messages Listen for, process and respond*/
4252 /* to DHCPV6 Client messages */
4253 /* */
4254 /* RELEASE HISTORY */
4255 /* */
4256 /* DATE NAME DESCRIPTION */
4257 /* */
4258 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4259 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4260 /* resulting in version 6.1 */
4261 /* */
4262 /**************************************************************************/
_nx_dhcpv6_validate_client_message(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_CLIENT * dhcpv6_client_ptr)4263 UINT _nx_dhcpv6_validate_client_message(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr)
4264 {
4265
4266 UINT status;
4267 UINT matching_clients;
4268 UINT matching_server_duids;
4269 UINT record_index;
4270 UINT dest_address_type;
4271 UINT ga_address_index;
4272 UINT if_index;
4273 UINT prefix_length;
4274
4275
4276 /* Clear the Server response to the Client. We will decide that below. */
4277 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = 0;
4278
4279 ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index;
4280
4281 /* Initialize the response to the client. If the client request is invalid, ignore the request (no response
4282 from server) or indicate the problem in the IANA status option. */
4283
4284 /* Initialize the IANA status for the SOLICIT request as successfully granted. */
4285 if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT)
4286 {
4287
4288 /* Respond to a valid Solicit request with an Advertise message. */
4289 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_ADVERTISE;
4290 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_SUCCESS;
4291 }
4292 else
4293 {
4294
4295 /* Respond to a valid Request request with a Reply message. */
4296 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_REPLY;
4297
4298 /* Set the expected IANA status. */
4299 if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) ||
4300 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) ||
4301 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND) ||
4302 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) ||
4303 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) ||
4304 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) ||
4305 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM))
4306 {
4307
4308 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_SUCCESS;
4309 }
4310 }
4311
4312 /* Never accept a packet without a DHCP ID. */
4313 if (!dhcpv6_client_ptr -> nx_dhcpv6_message_xid)
4314 {
4315
4316 /* Don't respond, just discard the message. . */
4317 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4318
4319 return(NX_SUCCESS);
4320 }
4321
4322 /* Determine if destination address type (unicast or multicast). */
4323 dest_address_type = IPv6_Address_Type(&dhcpv6_client_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]);
4324
4325 /* Do validation specific for message type. This section will also
4326 advance the DHCPv6 Client state and set the server response message type. */
4327 switch (dhcpv6_client_ptr -> nx_dhcpv6_message_type)
4328 {
4329
4330 case NX_DHCPV6_MESSAGE_TYPE_SOLICIT:
4331 {
4332
4333 /* Check for missing required fields. */
4334 if ((dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_type == 0) ||
4335 (dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == 0))
4336 {
4337
4338 /* Don't respond, just discard the message. . */
4339 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4340
4341 return(NX_SUCCESS);
4342 }
4343
4344 /* Check for presence of a server DUID. */
4345 if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw != 0)
4346 {
4347
4348 /* Don't respond, just discard the message. . */
4349 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4350
4351 /* Clear the success status. */
4352 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED;
4353
4354 return(NX_SUCCESS);
4355 }
4356
4357 /* The Solicit message should never be unicast. Check if the destination is unicast. */
4358 if (IPV6_ADDRESS_UNICAST & dest_address_type)
4359 {
4360
4361 /* Don't respond, just discard the message. . */
4362 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4363
4364 return NX_SUCCESS;
4365 }
4366 break;
4367 }
4368
4369 case NX_DHCPV6_MESSAGE_TYPE_REQUEST:
4370 case NX_DHCPV6_MESSAGE_TYPE_RENEW:
4371 case NX_DHCPV6_MESSAGE_TYPE_REBIND:
4372 case NX_DHCPV6_MESSAGE_TYPE_RELEASE:
4373 case NX_DHCPV6_MESSAGE_TYPE_DECLINE:
4374 {
4375
4376 /* Check for missing required fields. */
4377 if ((dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_type == 0) ||
4378 (dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == 0))
4379 {
4380
4381 /* Don't respond, just discard the message. . */
4382 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4383
4384 return(NX_SUCCESS);
4385 }
4386
4387 /* Check for an invalid unicast destination address type. */
4388 if (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_REBIND)
4389 {
4390
4391 /* The DHCPv6 server does not support unicast. Check for unicast client destination. */
4392 if (IPV6_ADDRESS_UNICAST & dest_address_type)
4393 {
4394
4395 /* It is unicast. Set the use multicast error status. */
4396 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_USE_MULTICAST;
4397
4398 return NX_SUCCESS;
4399 }
4400 }
4401
4402 /* This client message is not valid if an matching client record does not exist with the server. */
4403 status = _nx_dhcpv6_find_client_record_by_duid(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_client_duid,
4404 &record_index, NX_FALSE,
4405 dhcpv6_client_ptr -> nx_dhcpv6_message_xid,
4406 &matching_clients);
4407 /* Check for error. */
4408 if (status != NX_SUCCESS)
4409 {
4410
4411 return status;
4412 }
4413
4414 /* Check for matching client record. */
4415 if (!matching_clients)
4416 {
4417
4418 /* No matching client record found. */
4419
4420 /* For Release and Decline messages let the client know using the IANA status code that
4421 the server has no record of the assigned or requested address for this client. */
4422 if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) ||
4423 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE))
4424 {
4425
4426 /* Set the non-binding error status. */
4427 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_BINDING;
4428
4429 /* Set the lifetimes to zero. */
4430 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0;
4431 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0;
4432 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0;
4433 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0;
4434 }
4435 else
4436 {
4437
4438 /* Otherwise don't respond, just discard the message. */
4439 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4440
4441 /* Clear the success status. */
4442 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED;
4443
4444 return(NX_SUCCESS);
4445 }
4446 }
4447
4448 /* Handle Rebind a little differently. It should not specify a server DUID. */
4449 if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND)
4450 {
4451 /* Is there a server DUID in the client message? */
4452 if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_option_length > 0)
4453 {
4454
4455 /* Yes; don't respond, just discard the message. . */
4456 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4457
4458 /* Clear the success status. */
4459 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED;
4460 }
4461
4462 break;
4463 }
4464 else
4465 {
4466
4467 /* With all other IA addresses the server DUID must match the server DUID. */
4468 status = _nx_dhcpv6_check_duids_same(&dhcpv6_client_ptr -> nx_dhcpv6_server_duid,
4469 &dhcpv6_server_ptr -> nx_dhcpv6_server_duid, &matching_server_duids);
4470
4471 /* Check for error. */
4472 if (status != NX_SUCCESS)
4473 {
4474
4475 /* Clear the success status. */
4476 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED;
4477
4478 return status;
4479 }
4480
4481 /* Do the two server DUIDs match? */
4482 if (!matching_server_duids)
4483 {
4484
4485 /* No; don't respond, just discard the message. */
4486 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4487
4488 /* Clear the success status. */
4489 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED;
4490
4491 return NX_SUCCESS;
4492 }
4493 }
4494 break;
4495 }
4496 /* The Client wished to confirm its IP address is on link. */
4497 case NX_DHCPV6_MESSAGE_TYPE_CONFIRM:
4498 {
4499
4500 /* Check for missing IA option. */
4501 if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length == 0)
4502 {
4503
4504 /* No IA option, so don't respond, just discard the message. */
4505 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4506
4507 return NX_SUCCESS;
4508 }
4509
4510 /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the
4511 network masked addresses should be equal). */
4512 prefix_length = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length;
4513
4514 if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]),
4515 &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0],
4516 prefix_length))
4517 {
4518
4519
4520 /* Inform the client their IA address is not on link. */
4521 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_REPLY;
4522
4523 /* Set the IA-NA error status. */
4524 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NOT_ON_LINK;
4525
4526 return(NX_SUCCESS);
4527 }
4528
4529 /* More checks will be done when the client rebind address is searched in the server
4530 address table. For now we are ok. */
4531
4532 break;
4533 }
4534
4535 case NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST:
4536 {
4537
4538 /* Verify Client's server duid matches the server DUID. Note that if the server DUID type is a
4539 link layer time type (LLT), this comparison should ignore the time field because this is an 'asynchronous' request
4540 from the client, so just match on the LL data. */
4541
4542 /* Temporarily set the server DUID type to LL if it was LLT. */
4543 if ((dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) ||
4544 (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY))
4545 {
4546
4547 /* Now verify the physical address matches what the server has for this client. */
4548 if_index = dhcpv6_server_ptr -> nx_dhcpv6_server_interface_index;
4549 if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw !=
4550 dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_interface[if_index].nx_interface_physical_address_msw)
4551 {
4552
4553 /* Inform the client their physical address is not on record. */
4554 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4555 }
4556 else if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw !=
4557 dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_interface[if_index].nx_interface_physical_address_lsw)
4558 {
4559 /* Inform the client their physical address is not on record. */
4560 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4561 }
4562 }
4563 else
4564 {
4565
4566 /* Verify the client inform request was intended for this server. If the Client did not
4567 include a server DUID, which is acceptable in DHCPv6 protocol, it will 'pass' this check. */
4568 status = _nx_dhcpv6_check_duids_same(&dhcpv6_client_ptr -> nx_dhcpv6_server_duid,
4569 &dhcpv6_client_ptr -> nx_dhcpv6_server_duid, &matching_server_duids);
4570
4571 /* Check for error. */
4572 if (status != NX_SUCCESS)
4573 {
4574
4575 /* Clear the success status. */
4576 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED;
4577
4578 return status;
4579 }
4580
4581 /* Do the two server DUIDs match? */
4582 if (!matching_server_duids)
4583 {
4584
4585 /* Don't respond, just discard the message. */
4586 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4587
4588 /* Clear the success status. */
4589 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED;
4590
4591 return NX_SUCCESS;
4592 }
4593 }
4594
4595 /* Check for missing options request. */
4596 if (dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_option_length == 0)
4597 {
4598
4599 /* Don't respond, just discard the message. */
4600 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4601
4602 return NX_SUCCESS;
4603 }
4604
4605 break;
4606 }
4607
4608 default:
4609 {
4610
4611 dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT;
4612
4613 /* Clear the success status. */
4614 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED;
4615
4616 return(NX_SUCCESS);
4617
4618 /* No further processing to do. Leave the client state unchanged, whatever it was/is. */
4619 }
4620 }
4621
4622 return(NX_SUCCESS);
4623 }
4624
4625
4626 /**************************************************************************/
4627 /* */
4628 /* FUNCTION RELEASE */
4629 /* */
4630 /* _nx_dhcpv6_server_utility_get_block_option_length PORTABLE C */
4631 /* 6.1 */
4632 /* AUTHOR */
4633 /* */
4634 /* Yuxin Zhou, Microsoft Corporation */
4635 /* */
4636 /* DESCRIPTION */
4637 /* */
4638 /* This function parses the input buffer (assuming to be an option */
4639 /* block in a server reply) for option code and length. It assumes the */
4640 /* buffer pointer is pointed to the first byte of the option buffer. */
4641 /* */
4642 /* INPUT */
4643 /* */
4644 /* dhcpv6_ Pointer to DHCPv6 Client */
4645 /* option Option code of requested data */
4646 /* buffer_ptr Buffer to copy data to */
4647 /* length Size of buffer */
4648 /* valid */
4649 /* */
4650 /* OUTPUT */
4651 /* */
4652 /* status Completion status */
4653 /* NX_DHCPV6_OPTION_BLOCK_INCOMPLETE Unknown option specified */
4654 /* */
4655 /* CALLS */
4656 /* */
4657 /* _nx_dhcpv6_server_utility_get_data Parses a specific data from the */
4658 /* DHCPv6 option */
4659 /* */
4660 /* CALLED BY */
4661 /* */
4662 /* _nx_dhcpv6_server_utility_get_block_option_length */
4663 /* Parses option code and length */
4664 /* _nx_dhcpv6_server_extract_packet_information */
4665 /* Parses each option from server */
4666 /* reply and updates Client record */
4667 /* */
4668 /* RELEASE HISTORY */
4669 /* */
4670 /* DATE NAME DESCRIPTION */
4671 /* */
4672 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4673 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4674 /* resulting in version 6.1 */
4675 /* */
4676 /**************************************************************************/
_nx_dhcpv6_server_utility_get_block_option_length(UCHAR * buffer_ptr,ULONG * option,ULONG * length)4677 UINT _nx_dhcpv6_server_utility_get_block_option_length(UCHAR *buffer_ptr, ULONG *option, ULONG *length)
4678 {
4679
4680 /* Initialize to zero. */
4681 *option = 0;
4682 *length = 0;
4683
4684 /* First byte should be the op code. */
4685 _nx_dhcpv6_server_utility_get_data(buffer_ptr, 2, option);
4686
4687 buffer_ptr += 2;
4688
4689 /* Next byte should be the option length. */
4690 _nx_dhcpv6_server_utility_get_data(buffer_ptr, 2, length);
4691
4692 /* Buffer is now pointed at the data (past the length field). */
4693 buffer_ptr += 2;
4694
4695 /* Check for null data. */
4696 if (*option == 0 || *length == 0)
4697 {
4698
4699 return NX_DHCPV6_OPTION_BLOCK_INCOMPLETE;
4700 }
4701
4702 return(NX_SUCCESS);
4703
4704 }
4705
4706
4707 /**************************************************************************/
4708 /* */
4709 /* FUNCTION RELEASE */
4710 /* */
4711 /* _nx_dhcpv6_server_utility_get_data PORTABLE C */
4712 /* 6.1 */
4713 /* AUTHOR */
4714 /* */
4715 /* Yuxin Zhou, Microsoft Corporation */
4716 /* */
4717 /* DESCRIPTION */
4718 /* */
4719 /* This function parses the input buffer and returns numeric data */
4720 /* specified by the size argument, up to 4 bytes long. Note that if */
4721 /* caller is using this utility to extract bytes from a DHCPv6 packet */
4722 /* there is no need for byte swapping, as compared to using memcpy in */
4723 /* which case there is for little endian processors. */
4724 /* */
4725 /* INPUT */
4726 /* */
4727 /* buffer Pointer to data buffer */
4728 /* value Pointer to data parsed from buffer*/
4729 /* size Size of buffer */
4730 /* */
4731 /* OUTPUT */
4732 /* */
4733 /* NX_DHCPV6_INVALID_DATA_SIZE Requested data size too large */
4734 /* NX_SUCCESS Successful completion status */
4735 /* */
4736 /* CALLS */
4737 /* */
4738 /* None */
4739 /* */
4740 /* CALLED BY */
4741 /* _nx_dhcpv6_process_server_duid Process server duid in server reply*/
4742 /* _nx_dhcpv6_process_client_duid Process server duid in server reply*/
4743 /* _nx_dhcpv6_server_utility_get_block_option_length */
4744 /* Parses option code and length */
4745 /* _nx_dhcpv6_server_extract_packet_information */
4746 /* Parses each option from server */
4747 /* reply and updates Client record */
4748 /* */
4749 /* RELEASE HISTORY */
4750 /* */
4751 /* DATE NAME DESCRIPTION */
4752 /* */
4753 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4754 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4755 /* resulting in version 6.1 */
4756 /* */
4757 /**************************************************************************/
_nx_dhcpv6_server_utility_get_data(UCHAR * buffer,UINT size,ULONG * value)4758 UINT _nx_dhcpv6_server_utility_get_data(UCHAR *buffer, UINT size, ULONG *value)
4759 {
4760
4761
4762 /* Check that the size of the data fits in a ULONG. */
4763 if (size > sizeof(ULONG))
4764 {
4765 return NX_DHCPV6_INVALID_DATA_SIZE;
4766 }
4767
4768 *value = 0;
4769
4770 /* Process the data retrieval request. */
4771 while (size-- > 0)
4772 {
4773
4774 /* Build return value. */
4775 *value = (*value << 8) | *buffer++;
4776 }
4777
4778 /* Return value. */
4779 return NX_SUCCESS;
4780 }
4781
4782
4783 /**************************************************************************/
4784 /* */
4785 /* FUNCTION RELEASE */
4786 /* */
4787 /* _nx_dhcpv6_server_utility_time_randomize PORTABLE C */
4788 /* 6.1 */
4789 /* AUTHOR */
4790 /* */
4791 /* Yuxin Zhou, Microsoft Corporation */
4792 /* */
4793 /* DESCRIPTION */
4794 /* */
4795 /* This function returns a value of between -1 seconds and 1 second */
4796 /* in system ticks. It is used to randomize timeouts as required by */
4797 /* the RFC's so as to not overload a network server after power out. */
4798 /* */
4799 /* INPUT */
4800 /* */
4801 /* None */
4802 /* */
4803 /* OUTPUT */
4804 /* */
4805 /* ticks Number of ticks between 1 & -1*/
4806 /* */
4807 /* CALLS */
4808 /* */
4809 /* None */
4810 /* */
4811 /* CALLED BY */
4812 /* */
4813 /* _nx_dhcpv6_convert_delay_to_ticks Convert seconds to ticks */
4814 /* */
4815 /* RELEASE HISTORY */
4816 /* */
4817 /* DATE NAME DESCRIPTION */
4818 /* */
4819 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4820 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4821 /* resulting in version 6.1 */
4822 /* */
4823 /**************************************************************************/
_nx_dhcpv6_server_utility_time_randomize(void)4824 INT _nx_dhcpv6_server_utility_time_randomize(void)
4825 {
4826
4827 INT temp;
4828 UINT sign;
4829
4830
4831 temp = (INT)(NX_RAND() & 0x001F);
4832 sign = temp & 0x8;
4833
4834 /* Try for a number between 0 and 0x1F. */
4835 if (sign)
4836 {
4837 temp = -temp;
4838 }
4839
4840 return temp;
4841 }
4842
4843
4844 /**************************************************************************/
4845 /* */
4846 /* FUNCTION RELEASE */
4847 /* */
4848 /* _nx_dhcpv6_listen_for_messages PORTABLE C */
4849 /* 6.1 */
4850 /* AUTHOR */
4851 /* */
4852 /* Yuxin Zhou, Microsoft Corporation */
4853 /* */
4854 /* DESCRIPTION */
4855 /* */
4856 /* This function listens for DHCPv6 client messages. It validates and */
4857 /* extracts information for creating or updating the client record. It */
4858 /* also responds to the Client pending valid request is received, and */
4859 /* updates its client records. */
4860 /* */
4861 /* INPUT */
4862 /* */
4863 /* dhcpv6_ptr Pointer to DHCPv6 Server */
4864 /* */
4865 /* OUTPUT */
4866 /* */
4867 /* NX_SUCCESS Message handled successfully */
4868 /* NO_PACKET No packet received */
4869 /* NX_DHCP_BAD_INTERFACE_INDEX Packet interface not recognized*/
4870 /* status Actual completion outcome */
4871 /* */
4872 /* CALLS */
4873 /* */
4874 /* nx_packet_release Release DHCP packet */
4875 /* nx_udp_socket_receive Receive DHCP packet */
4876 /* _nx_dhcpv6_extract_information Extract DHCP packet info */
4877 /* _nx_dhcpv6_validate_client_message Process the Client message */
4878 /* _nx_dhcpv6_server_assign_ip_address Assign IP address to Client */
4879 /* _nx_dhcpv6_respond_to_client_message Create and send response back */
4880 /* _nx_dhcpv6_clear_client_session Clears client session data */
4881 /* */
4882 /* CALLED BY */
4883 /* */
4884 /* _nx_dhcpv6_server_thread_entry DHCPv6 Server thread task */
4885 /* */
4886 /* RELEASE HISTORY */
4887 /* */
4888 /* DATE NAME DESCRIPTION */
4889 /* */
4890 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4891 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4892 /* resulting in version 6.1 */
4893 /* */
4894 /**************************************************************************/
_nx_dhcpv6_listen_for_messages(NX_DHCPV6_SERVER * dhcpv6_server_ptr)4895 UINT _nx_dhcpv6_listen_for_messages(NX_DHCPV6_SERVER *dhcpv6_server_ptr)
4896 {
4897
4898 UINT status;
4899 UINT iface_index;
4900 NXD_ADDRESS source_address;
4901 NXD_ADDRESS destination_address;
4902 NX_IPV6_HEADER *ipv6_header_ptr;
4903 NX_PACKET *packet_ptr;
4904 NX_DHCPV6_CLIENT *dhcpv6_client_ptr;
4905 NX_DHCPV6_ADDRESS_LEASE *dhcpv6_interface_list_ptr;
4906 NX_PACKET *new_packet_ptr;
4907 ULONG bytes_copied = 0;
4908
4909
4910 /* Check for an incoming DHCPv6 packet with non blocking option. */
4911 status = nx_udp_socket_receive(&dhcpv6_server_ptr -> nx_dhcpv6_server_socket, &packet_ptr, NX_DHCPV6_PACKET_WAIT_OPTION);
4912
4913 /* Check for packet receive errors. */
4914 if (status != NX_SUCCESS)
4915 {
4916
4917 /* Return the packet receive status. */
4918 return(status);
4919 }
4920
4921 /* Check for valid packet length (message type and ID). */
4922 if (packet_ptr -> nx_packet_length < 4)
4923 {
4924
4925 /* Release the packet. */
4926 nx_packet_release(packet_ptr);
4927
4928 /* Return. */
4929 return(NX_DHCPV6_INVALID_DATA_SIZE);
4930 }
4931
4932 /* Get the interface index. */
4933 nxd_udp_packet_info_extract(packet_ptr, NX_NULL, NX_NULL, NX_NULL, &iface_index);
4934
4935 /* Does the DHCP server have a table for this packet interface? */
4936 if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
4937 {
4938
4939 /* No; Release the packet. */
4940 nx_packet_release(packet_ptr);
4941
4942 /* No, return the error status. */
4943 return(NX_DHCPV6_INVALID_INTERFACE_INDEX);
4944 }
4945
4946 /* Set a pointer to the IPv6 header to obtain source and destination address. */
4947 ipv6_header_ptr = (NX_IPV6_HEADER*)(packet_ptr -> nx_packet_ip_header);
4948
4949 /* Get the source address. */
4950 COPY_IPV6_ADDRESS(&ipv6_header_ptr -> nx_ip_header_source_ip[0], &source_address.nxd_ip_address.v6[0]);
4951 source_address.nxd_ip_version = NX_IP_VERSION_V6;
4952
4953 /* Get the destination address. */
4954 COPY_IPV6_ADDRESS(&ipv6_header_ptr -> nx_ip_header_destination_ip[0], &destination_address.nxd_ip_address.v6[0]);
4955 destination_address.nxd_ip_version = NX_IP_VERSION_V6;
4956
4957 /* We will copy the received packet (datagram) over to a packet from the DHCP Server pool and release
4958 the packet from the receive packet pool as soon as possible. */
4959 status = nx_packet_allocate(dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr, &new_packet_ptr, NX_IPv6_UDP_PACKET, NX_DHCPV6_PACKET_TIME_OUT);
4960
4961 /* Check status. */
4962 if (status != NX_SUCCESS)
4963 {
4964
4965 /* Release the original packet. */
4966 nx_packet_release(packet_ptr);
4967
4968 /* Error allocating packet, return error status. */
4969 return(status);
4970 }
4971
4972 /* Verify the incoming packet does not exceed our DHCP Server packet payload. */
4973 if ((ULONG)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < (packet_ptr -> nx_packet_length))
4974 {
4975
4976 /* Release the original packet. */
4977 nx_packet_release(packet_ptr);
4978
4979 /* Release the newly allocated packet and return an error. */
4980 nx_packet_release(new_packet_ptr);
4981
4982 return(NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD);
4983 }
4984
4985 /* Use a packet from the DHCP Server as a buffer to store the received packet data.
4986 Then we can release the received packet back to its packet pool. */
4987 status = nx_packet_data_extract_offset(packet_ptr, 0, (VOID *)new_packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length, &bytes_copied);
4988
4989 /* Check status. */
4990 if ((status != NX_SUCCESS) || (bytes_copied == 0))
4991 {
4992
4993 /* Release the original packet. */
4994 nx_packet_release(packet_ptr);
4995
4996 /* Release the allocated packet we'll never send. */
4997 nx_packet_release(new_packet_ptr);
4998
4999 /* Error extracting packet buffer, return error status. */
5000 return(status);
5001 }
5002
5003 /* Update the new packet with the bytes copied. For chained packets, this will reflect the total
5004 'datagram' length. */
5005 new_packet_ptr -> nx_packet_length = bytes_copied;
5006 new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_prepend_ptr + bytes_copied;
5007
5008 /* Now we can release the original packet. */
5009 nx_packet_release(packet_ptr);
5010
5011 /* Get the DHCPv6 Server Mutex. */
5012 tx_mutex_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex, NX_WAIT_FOREVER);
5013
5014 /* Extract the DHCPv6 specific information from the packet. This will create new Client record or update existing
5015 client record in the server table. */
5016 status = _nx_dhcpv6_server_extract_packet_information(dhcpv6_server_ptr, &dhcpv6_client_ptr, new_packet_ptr, iface_index, source_address, destination_address);
5017
5018 /* We are done with this packet now regardless of the success of the above operations. */
5019 nx_packet_release(new_packet_ptr);
5020
5021 /* Check if we have extracted a valid client record. */
5022 if (status != NX_SUCCESS)
5023 {
5024
5025 /* Not valid; is there a client record we need to clean up? */
5026 if (dhcpv6_client_ptr)
5027 {
5028
5029 /* Yes; clear the client record completely. */
5030 _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr);
5031 }
5032 else
5033 {
5034
5035 /* No record created; return the error status and abort. */
5036 tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex);
5037
5038 /* Return the error from extracting packet data. */
5039 return(status);
5040 }
5041 }
5042
5043 /* Determine if the server will respond to the message. */
5044 if ((dhcpv6_client_ptr == NX_NULL) ||
5045 (dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT))
5046 {
5047
5048 /* Release the mutex. */
5049 tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex);
5050
5051 /* No, no further processing necessary. */
5052 return NX_SUCCESS;
5053 }
5054
5055 /* Check if the server status indicates it will grant the client request. */
5056 if (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code == NX_DHCPV6_STATUS_SUCCESS)
5057 {
5058
5059 /* Yes it will. Check if the client is requesting an IP address, or renewing or rebinding a
5060 previously assigned one. */
5061 if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) ||
5062 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) ||
5063 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) ||
5064 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND))
5065 {
5066
5067 /* Yes, it is. This will (re)assign an IP address. */
5068 status = _nx_dhcpv6_assign_ip_address(dhcpv6_server_ptr, dhcpv6_client_ptr, &dhcpv6_interface_list_ptr);
5069
5070 /* Check for errors or no address assigned. */
5071 if (status != NX_SUCCESS)
5072 {
5073
5074 /* Release the mutex. */
5075 tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex);
5076
5077 /* Return all other errors as completion status. Do not send a message to the client.
5078 The server will otherwise wait for the client to try again. Do not clear client record. */
5079 return(status);
5080 }
5081
5082 /* Check if a valid IP address is available. */
5083 if (dhcpv6_interface_list_ptr)
5084 {
5085
5086 /* There is. DHCPv6 client has been assigned an IP address. */
5087
5088 /* Now ensure we are sending valid lease time parameters with the IP address. */
5089 if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST)
5090 {
5091
5092 /* Ignore invalid preferred or valid lifetimes from the client by setting to zero. */
5093 if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime > dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime)
5094 {
5095
5096 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0;
5097 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0;
5098 }
5099 /* Check for invalid T1 or T2 values; if out of range, set to zero). */
5100
5101 if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime &&
5102 (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime))
5103 {
5104 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0;
5105 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0;
5106 }
5107 else if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime &&
5108 (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 > dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime))
5109 {
5110 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0;
5111 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0;
5112 }
5113 else if (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2)
5114 {
5115 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0;
5116 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0;
5117 }
5118 }
5119 /* For a solicit message, ignore the preferred and valid lifetimes and check for
5120 valid T1 and T2 times. */
5121 else if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT)
5122 {
5123
5124 if (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2)
5125 {
5126 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0;
5127 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0;
5128 }
5129 }
5130
5131 /* If lifetime values are zero, or exceed the server default time, set to the default lease times. */
5132 if ((dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime == 0) ||
5133 (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime > NX_DHCPV6_DEFAULT_PREFERRED_TIME))
5134 {
5135
5136 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = NX_DHCPV6_DEFAULT_PREFERRED_TIME;
5137 }
5138 if ((dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime == 0) ||
5139 (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime > NX_DHCPV6_DEFAULT_VALID_TIME))
5140 {
5141
5142 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = NX_DHCPV6_DEFAULT_VALID_TIME;
5143 }
5144
5145 if ((dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 == 0) ||
5146 (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > NX_DHCPV6_DEFAULT_T1_TIME))
5147 {
5148
5149 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = NX_DHCPV6_DEFAULT_T1_TIME;
5150 }
5151
5152 if ((dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 == 0) ||
5153 (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 > NX_DHCPV6_DEFAULT_T2_TIME))
5154 {
5155
5156 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = NX_DHCPV6_DEFAULT_T2_TIME;
5157 }
5158
5159 /* Update the lease length in the server lease table. */
5160 dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_preferred_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime;
5161 dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_valid_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime;
5162 dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_T1_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1;
5163 dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_T2_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2;
5164
5165 /* Ok to copy this address into the client record. */
5166 COPY_NXD_ADDRESS(&dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_IP_address,
5167 &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address);
5168 }
5169 }
5170 }
5171
5172 /* Send the server reply back to the client. */
5173 status = _nx_dhcpv6_send_response_to_client(dhcpv6_server_ptr, dhcpv6_client_ptr);
5174
5175 /* Check if we need to remove the client record e.g. if the Client sent a Decline message. */
5176 if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) ||
5177 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE))
5178 {
5179
5180 /* This will clear the client record and in the case of
5181 a release message, return the IP address lease status to available. */
5182 status = _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr);
5183
5184 }
5185
5186 tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex);
5187
5188 /* Return actual outcome status. */
5189 return(status);
5190 }
5191
5192
5193 /**************************************************************************/
5194 /* */
5195 /* FUNCTION RELEASE */
5196 /* */
5197 /* _nx_dhcpv6_send_response_to_client PORTABLE C */
5198 /* 6.1.5 */
5199 /* AUTHOR */
5200 /* */
5201 /* Yuxin Zhou, Microsoft Corporation */
5202 /* */
5203 /* DESCRIPTION */
5204 /* */
5205 /* This function prepares DHCPv6 messages to send back to the Client. */
5206 /* Most of the information is obtained from the client session record. */
5207 /* */
5208 /* INPUT */
5209 /* */
5210 /* dhcpv6_server_ptr Pointer to DHCPv6 Server */
5211 /* dhcpv6_client_ptr Pointer to DHCPv6 Client */
5212 /* */
5213 /* OUTPUT */
5214 /* */
5215 /* status Completion status */
5216 /* */
5217 /* CALLS */
5218 /* */
5219 /* nx_packet_allocate Allocate a DHCPv6 packet */
5220 /* nx_packet_release Release DHCPv6 packet */
5221 /* nxd_udp_socket_send Send DHCPv6 packets */
5222 /* memcpy Copy specified area of memory */
5223 /* */
5224 /* CALLED BY */
5225 /* */
5226 /* _nx_dhcpv6_listen_for_messages Process Client DHCPv6 messages*/
5227 /* */
5228 /* RELEASE HISTORY */
5229 /* */
5230 /* DATE NAME DESCRIPTION */
5231 /* */
5232 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5233 /* 09-30-2020 Yuxin Zhou Modified comment(s), improved */
5234 /* packet length verification, */
5235 /* verified memcpy use cases, */
5236 /* resulting in version 6.1 */
5237 /* 03-02-2021 Yuxin Zhou Modified comment(s), and */
5238 /* fixed compiler warnings, */
5239 /* resulting in version 6.1.5 */
5240 /* */
5241 /**************************************************************************/
_nx_dhcpv6_send_response_to_client(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_CLIENT * dhcpv6_client_ptr)5242 UINT _nx_dhcpv6_send_response_to_client(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr)
5243 {
5244
5245 NX_PACKET *packet_ptr;
5246 UCHAR *buffer;
5247 UINT status;
5248 UINT buffer_index;
5249 ULONG message_word;
5250
5251
5252 /* Allocate a UDP packet from the DHCPv6 server packet pool. */
5253 status = nx_packet_allocate(dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr, &packet_ptr, NX_IPv6_UDP_PACKET, NX_DHCPV6_PACKET_TIME_OUT);
5254
5255 /* Was the packet allocation successful? */
5256 if (status != NX_SUCCESS)
5257 {
5258
5259 /* Return status. */
5260 return(status);
5261 }
5262
5263 /* Verify packet payload. */
5264 if ((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 4)
5265 {
5266 nx_packet_release(packet_ptr);
5267 return(NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD);
5268 }
5269
5270 /* Indicate this is an IPv6 packet. */
5271 packet_ptr -> nx_packet_ip_version = NX_IP_VERSION_V6;
5272
5273 /* Setup the packet buffer pointer. */
5274 buffer = packet_ptr -> nx_packet_prepend_ptr;
5275
5276 /* Clear the payload and packet interface field before preparing the packet for transmission. */
5277 memset(buffer, 0, (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr));
5278
5279 /* Now reduce it to three bytes. */
5280 dhcpv6_client_ptr -> nx_dhcpv6_message_xid = dhcpv6_client_ptr -> nx_dhcpv6_message_xid & 0x0ffffff;
5281
5282 /* Clear memory to make the message header. */
5283 memset(&message_word, 0, sizeof(ULONG));
5284
5285 /* Add the server message type and matching client transaction ID as the DHCPv6 header fields. */
5286 message_word = (ULONG)((dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server << 24) |
5287 (0x0FFFFFF & dhcpv6_client_ptr -> nx_dhcpv6_message_xid));
5288
5289 /* Adjust for endianness. */
5290 NX_CHANGE_ULONG_ENDIAN(message_word);
5291
5292 /* Copy the message header to the packet buffer. */
5293 memcpy(buffer, &message_word, sizeof(ULONG)); /* Use case of memcpy is verified. */
5294
5295 /* Update the buffer 'pointer'. */
5296 buffer_index = sizeof(ULONG);
5297
5298 /* Handle the special case of an Inform Request which does not include a Client identifier. */
5299 if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)
5300 {
5301
5302 status = NX_SUCCESS;
5303
5304 /* Only add the Client DUID if the client included one. */
5305 if (dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_op_code != 0)
5306 {
5307
5308 /* Add the Client DUID to the packet buffer. */
5309 status = _nx_dhcpv6_add_duid(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_client_duid, buffer,
5310 &buffer_index, NX_DHCPV6_CLIENT_DUID_TYPE);
5311 }
5312 }
5313 else
5314 {
5315
5316 /* Add the Client DUID to the packet buffer. */
5317 status = _nx_dhcpv6_add_duid(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_client_duid, buffer,
5318 &buffer_index, NX_DHCPV6_CLIENT_DUID_TYPE);
5319 }
5320
5321 /* Check for error. */
5322 if (status != NX_SUCCESS)
5323 {
5324 /* Release the allocated back to the DHCPv6 Server packet pool. */
5325 nx_packet_release(packet_ptr);
5326
5327 return status;
5328 }
5329
5330 /* Now add to the server DUID to the message. */
5331 status = _nx_dhcpv6_add_duid(dhcpv6_server_ptr, &dhcpv6_server_ptr -> nx_dhcpv6_server_duid, buffer,
5332 &buffer_index, NX_DHCPV6_SERVER_DUID_TYPE);
5333
5334 /* Check for error. */
5335 if (status != NX_SUCCESS)
5336 {
5337
5338 /* Release the allocated back to the DHCPv6 Server packet pool. */
5339 nx_packet_release(packet_ptr);
5340
5341 return status;
5342 }
5343
5344 /* Handle the special case of the Confirm request where we need only
5345 send a status option. */
5346 if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM)
5347 {
5348
5349 /* Update the IANA status message. */
5350 status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_TRUE);
5351
5352 if (status != NX_SUCCESS)
5353 {
5354 /* Release the allocated back to the DHCPv6 Server packet pool. */
5355 nx_packet_release(packet_ptr);
5356
5357 return status;
5358 }
5359
5360 /* Ok to just send a status option without the IANA option. */
5361 status = _nx_dhcpv6_add_iana_status(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_iana_status, buffer, &buffer_index);
5362
5363 /* Update the IANA status message. */
5364 status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_FALSE);
5365
5366 if (status != NX_SUCCESS)
5367 {
5368 /* Release the allocated back to the DHCPv6 Server packet pool. */
5369 nx_packet_release(packet_ptr);
5370
5371 return status;
5372 }
5373 }
5374
5375 /* Exclude IANA options from Confirm and Inform Request messages. */
5376 if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) &&
5377 (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_CONFIRM))
5378 {
5379
5380 /* Add the client IANA to the packet buffer. */
5381 status = _nx_dhcpv6_server_add_iana(dhcpv6_server_ptr, dhcpv6_client_ptr, buffer, &buffer_index);
5382
5383 /* Check for error. */
5384 if (status != NX_SUCCESS)
5385 {
5386 /* Release the allocated back to the DHCPv6 Server packet pool. */
5387 nx_packet_release(packet_ptr);
5388
5389 return status;
5390 }
5391 }
5392
5393 /* Only an Advertise response should include a preference. */
5394 if (dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_ADVERTISE)
5395
5396 {
5397
5398 status = _nx_dhcpv6_add_preference(dhcpv6_server_ptr, dhcpv6_client_ptr, buffer, &buffer_index);
5399 }
5400
5401 /* Check if the message type requires the server to add option request data. */
5402 if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) ||
5403 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) ||
5404 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST))
5405 {
5406
5407 /* It does. Did the Client ask for a requested option? Only provide information
5408 if there are no status errors from the server. */
5409 if (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code == NX_DHCPV6_STATUS_SUCCESS)
5410 {
5411
5412 /* Add the option request. */
5413 status = _nx_dhcpv6_add_option_requests(dhcpv6_server_ptr, dhcpv6_client_ptr, buffer, &buffer_index);
5414
5415 /* Check for internal error. */
5416 if (status != NX_SUCCESS)
5417 {
5418
5419 /* Release the allocated back to the DHCPv6 Server packet pool. */
5420 nx_packet_release(packet_ptr);
5421
5422 /* Return the error status and abort. */
5423 return status;
5424 }
5425 }
5426 }
5427
5428 /* Adjust the packet length for the DHCPv6 data. */
5429 packet_ptr -> nx_packet_length = buffer_index;
5430
5431 /* Update the packet pointer marking the end of the payload (DHCP) data. */
5432 packet_ptr -> nx_packet_append_ptr += buffer_index;
5433
5434 /* Send the response packet to the client. */
5435 status = nxd_udp_socket_interface_send(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), packet_ptr,
5436 &dhcpv6_client_ptr -> nx_dhcp_source_ip_address, NX_DHCPV6_CLIENT_UDP_PORT,
5437 dhcpv6_server_ptr -> nx_dhcpv6_server_interface_index);
5438
5439 /* Check for error. */
5440 if (status != NX_SUCCESS)
5441 {
5442 /* Release the allocated back to the DHCPv6 Server packet pool. */
5443 nx_packet_release(packet_ptr);
5444 }
5445 /* Return completion status. */
5446 return(status);
5447 }
5448
5449
5450 /**************************************************************************/
5451 /* */
5452 /* FUNCTION RELEASE */
5453 /* */
5454 /* _nx_dhcpc6_server_assign_ip_address PORTABLE C */
5455 /* 6.1 */
5456 /* AUTHOR */
5457 /* */
5458 /* Yuxin Zhou, Microsoft Corporation */
5459 /* */
5460 /* DESCRIPTION */
5461 /* */
5462 /* This service finds an available IP address for the client if none is */
5463 /* provided, and updates the client's record with the new IP address. It */
5464 /* updates the server IP address lease table with the assigned lease */
5465 /* status */
5466 /* */
5467 /* INPUT */
5468 /* */
5469 /* dhcpv6_server_ptr Pointer to DHCPV6 Server */
5470 /* dhcpv6_client_ptr Pointer to DHCPV6client */
5471 /* */
5472 /* OUTPUT */
5473 /* */
5474 /* NX_SUCCESS Successful completion */
5475 /* NX_DHCPV6_NO_AVAILABLE_IP_ADDRESSES No available address to assign*/
5476 /* */
5477 /* CALLS */
5478 /* */
5479 /* _nx_dhcp_find_interface_table_ip_address */
5480 /* Look up IP address in */
5481 /* server interface table */
5482 /* _nx_dhcp_find_ip_address_owner Look up owner of an IP address*/
5483 /* in server interfce table */
5484 /* _nx_dhcp_record_ip_address_owner Set the client as IP address */
5485 /* owner in interface table */
5486 /* */
5487 /* CALLED BY */
5488 /* */
5489 /* _nx_dhcpv6_listen_for_messages Process Client DHCPv6 messages*/
5490 /* */
5491 /* RELEASE HISTORY */
5492 /* */
5493 /* DATE NAME DESCRIPTION */
5494 /* */
5495 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5496 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5497 /* resulting in version 6.1 */
5498 /* */
5499 /**************************************************************************/
_nx_dhcpv6_assign_ip_address(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_CLIENT * dhcpv6_client_ptr,NX_DHCPV6_ADDRESS_LEASE ** interface_address_ptr)5500 UINT _nx_dhcpv6_assign_ip_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr,
5501 NX_DHCPV6_ADDRESS_LEASE **interface_address_ptr)
5502 {
5503 UINT status;
5504 UINT i;
5505 NX_DHCPV6_ADDRESS_LEASE *temp_interface_address_ptr;
5506 UINT matching;
5507
5508
5509 /* Initialize outcome to no address assigned. */
5510 *interface_address_ptr = NX_NULL;
5511
5512 /* Does the Client have a IP address already assigned? */
5513 if (!CHECK_UNSPECIFIED_ADDRESS(&dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0]))
5514 {
5515
5516 /* Yes; The client has an IP address. */
5517
5518 /* Check if this address exists in the Server IP address list. */
5519 status = _nx_dhcpv6_find_ip_address(dhcpv6_server_ptr, dhcpv6_client_ptr, &temp_interface_address_ptr);
5520
5521 /* Check for internal errors. */
5522 if (status != NX_SUCCESS)
5523 {
5524
5525 return status;
5526 }
5527
5528 /* Was the address found in the server table? */
5529 if (temp_interface_address_ptr)
5530 {
5531
5532 matching = NX_FALSE;
5533
5534 /* Verify the server has assigned this address. */
5535 if (temp_interface_address_ptr -> nx_dhcpv6_lease_assigned_to)
5536 {
5537 /* It has; now werify it is assigned to this client. */
5538 status = _nx_dhcpv6_check_duids_same(&dhcpv6_client_ptr -> nx_dhcpv6_client_duid,
5539 &(temp_interface_address_ptr -> nx_dhcpv6_lease_assigned_to -> nx_dhcpv6_client_duid),
5540 &matching);
5541
5542 /* Check for internal errors. */
5543 if (status != NX_SUCCESS)
5544 {
5545
5546 return status;
5547 }
5548 }
5549 else
5550 {
5551 /* It has not (so it is available). Assign it to this client. */
5552
5553 /* Set the lease address entry in the server table. */
5554 *interface_address_ptr = temp_interface_address_ptr;
5555
5556 /* Mark the owner of the lease as this client. */
5557 temp_interface_address_ptr -> nx_dhcpv6_lease_assigned_to = dhcpv6_client_ptr;
5558
5559 /* We are all done. */
5560 return NX_SUCCESS;
5561 }
5562
5563 /* Was the address assigned to this client previously? */
5564 if (matching)
5565 {
5566
5567 /* Yes, return a pointer to the IP lease in the server table. */
5568 *interface_address_ptr = temp_interface_address_ptr;
5569
5570 /* We will (re)assign this IP address to the client. */
5571 return NX_SUCCESS;
5572 }
5573 else
5574 {
5575 /* No this address is not available. */
5576
5577 /* Is it Ok to assign another IP address only if this is a Solicit request? */
5578 if (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_SOLICIT)
5579 {
5580
5581 /* No; Reply back the client request can not be granted. */
5582 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_BINDING;
5583
5584 /* Because the server can not validate the IP address to assign,
5585 set the lifetimes to zero RFC 3315 Sect 18.2.3, 18.2.4. */
5586 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0;
5587 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0;
5588 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0;
5589 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0;
5590
5591 dhcpv6_client_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND;
5592
5593 return NX_SUCCESS;
5594 }
5595 }
5596 }
5597 else
5598 {
5599
5600 /* Client address not found in table. */
5601
5602 /* Ok to assign another IP address only if this is a Solicit request? */
5603 if (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_SOLICIT)
5604 {
5605
5606 /* No; reply backthe client request can not be granted. */
5607 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_BINDING;
5608
5609 /* Because the server can not validate the IP address to assign, set the lifetimes to zero RFC 3315 Sect 18.2.3, 18.2.4. */
5610 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0;
5611 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0;
5612 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0;
5613 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0;
5614
5615 dhcpv6_client_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND;
5616
5617 return NX_SUCCESS;
5618 }
5619 }
5620 }
5621
5622 /* If we reach this point, we need to find an available address for the client. */
5623 for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++)
5624 {
5625
5626 if (!dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to)
5627 {
5628 break;
5629 }
5630 }
5631
5632 /* Check if we found anything. */
5633 if (i == NX_DHCPV6_MAX_LEASES)
5634 {
5635
5636 /* No; reply back there are no addresses available. */
5637 dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_ADDRS_AVAILABLE;
5638
5639 /* Because the server can not assign the IP address, set the lifetimes to zero RFC 3315 Sect 18.2.3, 18.2.4. */
5640 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0;
5641 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0;
5642 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0;
5643 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0;
5644
5645 dhcpv6_client_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND;
5646 }
5647 else
5648 {
5649
5650 /* Found an empty slot; assign it to this client. */
5651
5652 /* Mark the owner of the lease as this client. */
5653 dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = dhcpv6_client_ptr;
5654
5655 /* Return the lease address entry in the server table. */
5656 *interface_address_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]);
5657 }
5658
5659 return NX_SUCCESS;
5660 }
5661
5662
5663 /**************************************************************************/
5664 /* */
5665 /* FUNCTION RELEASE */
5666 /* */
5667 /* _nx_dhcp_find_client_record_by_chaddr PORTABLE C */
5668 /* 6.1 */
5669 /* AUTHOR */
5670 /* */
5671 /* Yuxin Zhou, Microsoft Corporation */
5672 /* */
5673 /* DESCRIPTION */
5674 /* */
5675 /* This function looks up a client record by the client hardware mac */
5676 /* address. */
5677 /* */
5678 /* INPUT */
5679 /* */
5680 /* dhcpv6_server_ptr Pointer to DHCPv6 Server */
5681 /* dhcpv6_duid _ptr Pointer to client DUID */
5682 /* record_index Index of client record found */
5683 /* in server table */
5684 /* add_on Option to add if not found */
5685 /* message_xid Message transaction ID */
5686 /* matching Indicates if client existed in*/
5687 /* server records already */
5688 /* */
5689 /* OUTPUT */
5690 /* */
5691 /* NX_SUCCESS Message handled successfully */
5692 /* NX_DHCPV6_TABLE_FULL Client record table is full */
5693 /* */
5694 /* CALLS */
5695 /* _nx_dhcpv6_check_duids_same Checks if DUIDs are the same */
5696 /* */
5697 /* CALLED BY */
5698 /* */
5699 /* _nx_dhcpv6_server_extract_packet_information */
5700 /* Extract DHCPv6 info from */
5701 /* Client message */
5702 /* */
5703 /* RELEASE HISTORY */
5704 /* */
5705 /* DATE NAME DESCRIPTION */
5706 /* */
5707 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5708 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5709 /* resulting in version 6.1 */
5710 /* */
5711 /**************************************************************************/
_nx_dhcpv6_find_client_record_by_duid(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_SVR_DUID * duid_ptr,UINT * record_index,UINT add_on,ULONG message_xid,UINT * matching)5712 UINT _nx_dhcpv6_find_client_record_by_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SVR_DUID *duid_ptr,
5713 UINT *record_index, UINT add_on, ULONG message_xid, UINT *matching)
5714 {
5715
5716 UINT i;
5717 UINT status;
5718 UINT available_index;
5719 NX_DHCPV6_CLIENT *client_record_ptr;
5720
5721
5722 /* Initialize result to not found. */
5723 *matching = NX_FALSE;
5724
5725 /* Initialize an available slot in the table as outside the boundary (e.g. no slots available). */
5726 available_index = NX_DHCPV6_MAX_CLIENTS;
5727
5728 /* Records are not necessarily added and deleted sequentially,
5729 so search the whole table until a match is found. */
5730 i = 0;
5731 status = NX_SUCCESS;
5732
5733 while (i < NX_DHCPV6_MAX_CLIENTS)
5734 {
5735
5736 /* Set local pointer for convenience. */
5737 client_record_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i];
5738
5739 /* Skip empty records. */
5740 if (!client_record_ptr -> nx_dhcpv6_id)
5741 {
5742
5743 /* Flag the first empty record in case we need to add the current client to the table. */
5744 if (i < available_index)
5745 available_index = i;
5746
5747 i++;
5748
5749 continue;
5750 }
5751
5752 status = _nx_dhcpv6_check_duids_same(&client_record_ptr -> nx_dhcpv6_client_duid, duid_ptr, matching);
5753
5754 /* Check the DUID in the received client request against the server record. */
5755 if ((status == NX_SUCCESS) && *matching)
5756 {
5757
5758 client_record_ptr -> nx_dhcpv6_message_xid = message_xid;
5759
5760
5761 /* Reset the client session time every time we hear from a client. */
5762 client_record_ptr -> nx_dhcpv6_client_session_time = 1;
5763
5764 /* Got a match! Return the client record location. */
5765 *record_index = i;
5766
5767 /* Set the result to client located. */
5768 *matching = NX_TRUE;
5769
5770 return(NX_SUCCESS);
5771 }
5772
5773 /* No match. Check the next client in the server table. */
5774 i++;
5775 }
5776
5777 /* Not found. Create a record for this client? */
5778 if (!add_on)
5779 {
5780
5781 /* Do not create a record and handle as an error. */
5782 return(NX_DHCPV6_CLIENT_RECORD_NOT_FOUND);
5783 }
5784
5785 /* Check if there is available room in the table for a new client. */
5786 if (available_index >= NX_DHCPV6_MAX_CLIENTS)
5787 {
5788
5789 /* No, we cannot add this client so the server's table. */
5790 return(NX_DHCPV6_TABLE_FULL);
5791 }
5792
5793 /* Set local pointer to an available slot. */
5794 client_record_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[available_index];
5795
5796 /* Return the location of the newly created client record. */
5797 *record_index = available_index;
5798
5799 return(NX_SUCCESS);
5800 }
5801
5802
5803 /**************************************************************************/
5804 /* */
5805 /* FUNCTION RELEASE */
5806 /* */
5807 /* _nx_dhcpv6_find_ip_address PORTABLE C */
5808 /* 6.1 */
5809 /* AUTHOR */
5810 /* */
5811 /* Yuxin Zhou, Microsoft Corporation */
5812 /* */
5813 /* DESCRIPTION */
5814 /* */
5815 /* This function looks up a client DHCPv6 message IP address in the */
5816 /* appropriate server IP address table, based on the client network */
5817 /* interface index. For single homed hosts, this defaults to zero. */
5818 /* */
5819 /* INPUT */
5820 /* */
5821 /* dhcpv6_server_ptr Pointer to DHCPv6 Server */
5822 /* dhcpv6_client_ptr Pointer to DHCPv6 client */
5823 /* interface_address_ptr Pointer to matching entry */
5824 /* */
5825 /* OUTPUT */
5826 /* */
5827 /* NX_SUCCESS Search completes successfully */
5828 /* */
5829 /* CALLS */
5830 /* */
5831 /* _nx_dhcp_clear_client_record Removes client record from */
5832 /* server table */
5833 /* */
5834 /* CALLED BY */
5835 /* */
5836 /* CHECK_IPV6_ADDRESSES_SAME Does IPv6 address comparison */
5837 /* */
5838 /* RELEASE HISTORY */
5839 /* */
5840 /* DATE NAME DESCRIPTION */
5841 /* */
5842 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5843 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5844 /* resulting in version 6.1 */
5845 /* */
5846 /**************************************************************************/
_nx_dhcpv6_find_ip_address(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_CLIENT * dhcpv6_client_ptr,NX_DHCPV6_ADDRESS_LEASE ** interface_address_ptr)5847 UINT _nx_dhcpv6_find_ip_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr,
5848 NX_DHCPV6_ADDRESS_LEASE **interface_address_ptr)
5849 {
5850
5851 UINT i;
5852 NXD_ADDRESS server_table_address;
5853
5854
5855 /* Initialize to not found. */
5856 *interface_address_ptr = NX_NULL;
5857
5858 /* Search through the interface specific address table. For single homed hosts, there is only one address table. */
5859 for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++)
5860 {
5861
5862 /* Get a pointer to the address, using the client's interface index to access the correct IP address table. */
5863 server_table_address = dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_IP_address;
5864
5865 /* Check for a match. */
5866 if (CHECK_IPV6_ADDRESSES_SAME(&server_table_address.nxd_ip_address.v6[0],
5867 &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0]))
5868 {
5869
5870 /* Set the location of the matching server entry, to indicate we found a match. */
5871 *interface_address_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i];
5872 break;
5873 }
5874 }
5875
5876 return NX_SUCCESS;
5877 }
5878
5879
5880 /**************************************************************************/
5881 /* */
5882 /* FUNCTION RELEASE */
5883 /* */
5884 /* _nx_dhcpv6_clear_client_record PORTABLE C */
5885 /* 6.1 */
5886 /* AUTHOR */
5887 /* */
5888 /* Yuxin Zhou, Microsoft Corporation */
5889 /* */
5890 /* DESCRIPTION */
5891 /* */
5892 /* This function clears the entire client record from the server table.*/
5893 /* It also frees up the client's IP address in the server IP address */
5894 /* table. */
5895 /* */
5896 /* INPUT */
5897 /* */
5898 /* dhcpv6_ptr Pointer to DHCPV6 Server */
5899 /* dhcpv6_client_ptr Pointer to DHCPV6 Client */
5900 /* */
5901 /* OUTPUT */
5902 /* */
5903 /* NX_SUCCESS Successful outcome */
5904 /* NX_DHCP_BAD_INTERFACE_INDEX Invalid client interface index */
5905 /* CALLS */
5906 /* */
5907 /* tx_mutex_get Get server protection mutex */
5908 /* tx_mutex_put Release server protection mutex*/
5909 /* */
5910 /* CALLED BY */
5911 /* */
5912 /* _nx_dhcpv6_listen_for_messages Listen for client requests */
5913 /* _nx_dhcpv6_find_client_record_by_chaddr */
5914 /* Find client in server table */
5915 /* */
5916 /* RELEASE HISTORY */
5917 /* */
5918 /* DATE NAME DESCRIPTION */
5919 /* */
5920 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5921 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5922 /* resulting in version 6.1 */
5923 /* */
5924 /**************************************************************************/
_nx_dhcpv6_clear_client_record(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_CLIENT * dhcpv6_client_ptr)5925 UINT _nx_dhcpv6_clear_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr)
5926 {
5927
5928 UINT i;
5929
5930
5931 if (!dhcpv6_client_ptr)
5932 {
5933
5934 /* Benign error. Return success. */
5935 return(NX_SUCCESS);
5936 }
5937
5938 i = 0;
5939
5940 /* Does the client have an assigned IP address? */
5941 if (!CHECK_UNSPECIFIED_ADDRESS(&dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0]))
5942 {
5943
5944 /* Yes, We need to free up the Client's assigned IP address in the server database. */
5945 while (i < NX_DHCPV6_MAX_LEASES)
5946 {
5947
5948 tx_mutex_get(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex), NX_WAIT_FOREVER);
5949
5950 /* Find the interface table entry by matching IP address. */
5951 if (CHECK_IPV6_ADDRESSES_SAME(&dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0],
5952 &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0]))
5953 {
5954
5955 /* Clear the IP address list item properties. */
5956 if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE)
5957 {
5958
5959 /* Apparently another client has this address so do not clear the assignment status. */
5960 dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = (NX_DHCPV6_CLIENT *)(ALIGN_TYPE)0xFFFFFFFF;
5961 }
5962 else
5963 {
5964
5965 /* Restore availability by clearing the owner. */
5966 dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = NX_NULL;
5967 }
5968
5969 dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_T1_lifetime = 0;
5970 dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_T2_lifetime = 0;
5971 dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_valid_lifetime = 0;
5972 dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_preferred_lifetime = 0;
5973
5974 tx_mutex_put(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex));
5975
5976 /* Address now available for DHCP client. */
5977 break;
5978 }
5979 i++;
5980
5981 tx_mutex_put(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex));
5982
5983 }
5984 }
5985
5986 /* Ok to clear the Client record. */
5987 memset(dhcpv6_client_ptr, 0, sizeof(NX_DHCPV6_CLIENT));
5988
5989 return(NX_SUCCESS);
5990 }
5991
5992
5993 /**************************************************************************/
5994 /* */
5995 /* FUNCTION RELEASE */
5996 /* */
5997 /* _nx_dhcpv6_update_client_record PORTABLE C */
5998 /* 6.1 */
5999 /* AUTHOR */
6000 /* */
6001 /* Yuxin Zhou, Microsoft Corporation */
6002 /* */
6003 /* DESCRIPTION */
6004 /* */
6005 /* This function updates the client record based on the most recent */
6006 /* message received from the client. A typical example is after a */
6007 /* Solicit message is received the server gets a Request message which */
6008 /* it will add to the client record it has in its table. */
6009 /* */
6010 /* INPUT */
6011 /* */
6012 /* dhcpv6_server_ptr Pointer to DHCPV6 Server */
6013 /* to_server_ptr Pointer to client to update */
6014 /* from_client_ptr Pointer to client updated from */
6015 /* */
6016 /* OUTPUT */
6017 /* */
6018 /* NX_SUCCESS Successful outcome */
6019 /* */
6020 /* CALLS */
6021 /* */
6022 /* memcpy Copy specified area of memory */
6023 /* */
6024 /* CALLED BY */
6025 /* */
6026 /* _nx_dhcpv6_server_extract_packet_information */
6027 /* Process DHCPv6 data in packet */
6028 /* */
6029 /* RELEASE HISTORY */
6030 /* */
6031 /* DATE NAME DESCRIPTION */
6032 /* */
6033 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6034 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
6035 /* verified memcpy use cases, */
6036 /* resulting in version 6.1 */
6037 /* */
6038 /**************************************************************************/
_nx_dhcpv6_update_client_record(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_CLIENT * from_extracted_client_data_ptr,NX_DHCPV6_CLIENT * to_client_data_on_record_ptr)6039 UINT _nx_dhcpv6_update_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr,
6040 NX_DHCPV6_CLIENT *from_extracted_client_data_ptr,
6041 NX_DHCPV6_CLIENT *to_client_data_on_record_ptr)
6042 {
6043
6044 NX_PARAMETER_NOT_USED(dhcpv6_server_ptr);
6045
6046 /* If this is a solicit message update the entire copy into the specified record. */
6047 if (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT)
6048 {
6049
6050 /* Ok to copy the whole record over. */
6051 memcpy(to_client_data_on_record_ptr, from_extracted_client_data_ptr, sizeof(NX_DHCPV6_CLIENT)); /* Use case of memcpy is verified. */
6052
6053 /* Update various fields now that the client is in a DHCPv6 session with the server. */
6054 to_client_data_on_record_ptr -> nx_dhcpv6_client_session_time = 1;
6055 memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_client_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_SVR_DUID)); /* Use case of memcpy is verified. */
6056 memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_server_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_SVR_DUID)); /* Use case of memcpy is verified. */
6057 }
6058 else if (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)
6059 {
6060
6061 /* Update selected fields for an INFORM REQUEST. */
6062 to_client_data_on_record_ptr -> nx_dhcpv6_id = from_extracted_client_data_ptr -> nx_dhcpv6_id;
6063 to_client_data_on_record_ptr -> nx_dhcpv6_message_xid = from_extracted_client_data_ptr -> nx_dhcpv6_message_xid;
6064 to_client_data_on_record_ptr -> nx_dhcpv6_message_type = from_extracted_client_data_ptr -> nx_dhcpv6_message_type;
6065 to_client_data_on_record_ptr -> nx_dhcpv6_response_back_from_server = from_extracted_client_data_ptr -> nx_dhcpv6_response_back_from_server;
6066
6067 COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0],
6068 &to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0]);
6069 to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
6070
6071 COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0],
6072 &to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]);
6073 to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
6074
6075 memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_option_request, &from_extracted_client_data_ptr -> nx_dhcpv6_option_request, sizeof(NX_DHCPV6_SERVER_OPTIONREQUEST)); /* Use case of memcpy is verified. */
6076 memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_client_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_SVR_DUID)); /* Use case of memcpy is verified. */
6077 memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_server_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_SVR_DUID)); /* Use case of memcpy is verified. */
6078
6079 }
6080 /* If this is not a solicit message, update the selected fields into the specified record. */
6081 else if ((from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) ||
6082 (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) ||
6083 (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND) ||
6084 (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) ||
6085 (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) ||
6086 (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM))
6087 {
6088
6089
6090 /* Ok to update the existing client record.
6091
6092 Note: if this is a duplicate client request we update the client record just
6093 the same. */
6094 to_client_data_on_record_ptr -> nx_dhcpv6_id = from_extracted_client_data_ptr -> nx_dhcpv6_id;
6095 to_client_data_on_record_ptr -> nx_dhcpv6_message_xid = from_extracted_client_data_ptr -> nx_dhcpv6_message_xid;
6096 to_client_data_on_record_ptr -> nx_dhcpv6_message_type = from_extracted_client_data_ptr -> nx_dhcpv6_message_type;
6097 to_client_data_on_record_ptr -> nx_dhcpv6_response_back_from_server = from_extracted_client_data_ptr -> nx_dhcpv6_response_back_from_server;
6098
6099 memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_client_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_SVR_DUID)); /* Use case of memcpy is verified. */
6100 memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_server_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_SVR_DUID)); /* Use case of memcpy is verified. */
6101 memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_elapsed_time, &from_extracted_client_data_ptr -> nx_dhcpv6_elapsed_time, sizeof(NX_DHCPV6_SERVER_ELAPSED_TIME)); /* Use case of memcpy is verified. */
6102 memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_iana, &from_extracted_client_data_ptr -> nx_dhcpv6_iana, sizeof(NX_DHCPV6_SERVER_IA_NA)); /* Use case of memcpy is verified. */
6103 memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_ia, &from_extracted_client_data_ptr -> nx_dhcpv6_ia, sizeof(NX_DHCPV6_SERVER_IA_ADDRESS)); /* Use case of memcpy is verified. */
6104
6105 /* Update the IANA status option code, length and status message. The DHCPv6 server
6106 will figure out the actual lenght with the status message text added in later. */
6107 to_client_data_on_record_ptr -> nx_dhcpv6_iana_status.nx_status_code = from_extracted_client_data_ptr -> nx_dhcpv6_iana_status.nx_status_code;
6108 to_client_data_on_record_ptr -> nx_dhcpv6_iana_status.nx_option_length = sizeof(USHORT);
6109
6110 COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0],
6111 &to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0]);
6112
6113 to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
6114
6115 COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0],
6116 &to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]);
6117
6118 to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
6119
6120 memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_option_request, &from_extracted_client_data_ptr -> nx_dhcpv6_option_request, sizeof(NX_DHCPV6_SERVER_OPTIONREQUEST)); /* Use case of memcpy is verified. */
6121
6122 /* Update fields based on the state of the client. At this point the client is bound to a
6123 valid IP address to the session is 'over'. Set timeout fields to stop the session timer
6124 and begin the lease life timer. */
6125 to_client_data_on_record_ptr -> nx_dhcpv6_client_session_time = 0;
6126
6127 /* Start the lease timer if we have just (re)assigned an IP lease. */
6128 if ((from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) ||
6129 (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) ||
6130 (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND))
6131 {
6132
6133 to_client_data_on_record_ptr -> nx_dhcpv6_IP_lease_time_accrued = 1;
6134 to_client_data_on_record_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND;
6135 }
6136
6137 /* No need to set the client state to unbound. We will remove the client record and restore the
6138 IP address status back to available after sending the server reply. */
6139 }
6140 /* else
6141 Confirm, Inform Request and other messages should not change the client record. */
6142
6143 return NX_SUCCESS;
6144 }
6145
6146
6147 /**************************************************************************/
6148 /* */
6149 /* FUNCTION RELEASE */
6150 /* */
6151 /* _nx_dhcpv6_server_process_iana PORTABLE C */
6152 /* 6.1 */
6153 /* AUTHOR */
6154 /* */
6155 /* Yuxin Zhou, Microsoft Corporation */
6156 /* */
6157 /* DESCRIPTION */
6158 /* */
6159 /* This function extracts the IANA option from a client DHCPv6 message.*/
6160 /* */
6161 /* INPUT */
6162 /* */
6163 /* dhcpv6_client_ptr Pointer to DHCPV6 Client instance */
6164 /* option_code Option code */
6165 /* option_length Size of option data */
6166 /* option_data Pointer to option data */
6167 /* */
6168 /* OUTPUT */
6169 /* */
6170 /* status Actual completion status */
6171 /* NX_DHCPV6_INVALID_IANA_DATA IANA option is missing data or */
6172 /* improperly formatted */
6173 /* CALLS */
6174 /* */
6175 /* _nx_dhcpv6_server_utility_get_data */
6176 /* Parses data from packet buffer */
6177 /* _nx_dhcpv6_server_utility_get_block_option_length */
6178 /* Parses option header from buffer */
6179 /* */
6180 /* CALLED BY */
6181 /* */
6182 /* _nx_dhcpv6_server_extract_packet_information */
6183 /* Extracts DHCPV6 data from packet */
6184 /* */
6185 /* RELEASE HISTORY */
6186 /* */
6187 /* DATE NAME DESCRIPTION */
6188 /* */
6189 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6190 /* 09-30-2020 Yuxin Zhou Modified comment(s), improved */
6191 /* packet length verification, */
6192 /* resulting in version 6.1 */
6193 /* */
6194 /**************************************************************************/
_nx_dhcpv6_server_process_iana(NX_DHCPV6_CLIENT * dhcpv6_client_ptr,ULONG option_code,UINT option_length,UCHAR * option_data)6195 UINT _nx_dhcpv6_server_process_iana(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, ULONG option_code, UINT option_length, UCHAR *option_data)
6196 {
6197
6198 UINT status;
6199 ULONG data;
6200 UINT index;
6201 ULONG iana_option_code, iana_option_length;
6202 UINT process_ia_option;
6203
6204
6205 /* Initialize local variables. */
6206 process_ia_option = NX_TRUE;
6207 index = 0;
6208
6209 /* Set option code and length. */
6210 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_op_code = (USHORT)option_code;
6211 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_option_length = (USHORT)option_length;
6212
6213 /* Check option length for IANA ID. */
6214 if (option_length < 4)
6215 {
6216 return(NX_DHCPV6_INVALID_IANA_DATA);
6217 }
6218
6219 /* The first word should contain the IANA ID. */
6220 _nx_dhcpv6_server_utility_get_data(option_data + index, sizeof(ULONG), &data);
6221
6222 /* Process the IANA ID. */
6223 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_IA_NA_id = data;
6224
6225 /* Update the write location index. */
6226 index += 4;
6227
6228 /* Check option length for T1 and T2. */
6229 if (index + 8 > option_length)
6230 {
6231 return(NX_DHCPV6_INVALID_IANA_DATA);
6232 }
6233
6234 /* Copy T1 and T2 from the buffer into IANA. */
6235 _nx_dhcpv6_server_utility_get_data(option_data + index, sizeof(ULONG), &data);
6236 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = data;
6237 index += (ULONG)sizeof(ULONG);
6238
6239 _nx_dhcpv6_server_utility_get_data(option_data + index, sizeof(ULONG), &data);
6240 dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = data;
6241 index += (ULONG)sizeof(ULONG);
6242
6243 /* Check for invalid T1/T2 lifetimes. */
6244 if (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2)
6245 {
6246
6247 /* Reject the server DHCPv6 response. */
6248 return NX_DHCPV6_INVALID_IANA_TIME;
6249 }
6250
6251 /* Check if we're at the end of option data yet. */
6252 if (index == option_length)
6253 {
6254
6255 /* Yes, all done. */
6256 return NX_SUCCESS;
6257 }
6258
6259 /* Now we recurse into the options embedded in the IANA option. We do it here
6260 because this is part of the IANA option data length. */
6261 while (index + 4 <= option_length)
6262 {
6263
6264 /* Get the next option code and length. */
6265 status = _nx_dhcpv6_server_utility_get_block_option_length(option_data + index, &iana_option_code, &iana_option_length);
6266
6267 /* Check that the block data is valid. */
6268 if (status != NX_SUCCESS)
6269 {
6270
6271 /* No, return the error status. */
6272 return status;
6273 }
6274
6275 /* Skip IA option code and length. */
6276 index += 4;
6277
6278 /* This is a double check to verify we haven't gone off the end of the packet buffer. */
6279 if (index + iana_option_length > option_length)
6280 {
6281 return (NX_DHCPV6_INVALID_IANA_DATA);
6282 }
6283
6284 /* Check if this is an IA address option request, and if we have already
6285 processed an IA in this message (the DHCPv6 server is limited to
6286 one IA per client message). */
6287 if (iana_option_code == NX_DHCPV6_OP_IA_ADDRESS)
6288 {
6289
6290 /* Yes it is, so process it. */
6291 status = _nx_dhcpv6_server_process_ia(dhcpv6_client_ptr, iana_option_code, iana_option_length, (option_data + index), process_ia_option);
6292
6293 /* Check for errors processing the DHCPv6 message. */
6294 if (status != NX_SUCCESS)
6295 {
6296
6297 /* Abort further processing. Return error status. */
6298 return status;
6299 }
6300
6301 /* Indicate we already have an IA option if the client request contains multiple IAs. */
6302 process_ia_option = NX_FALSE;
6303 }
6304
6305 /* Keep track of how far into the packet we have parsed. */
6306 index += iana_option_length;
6307 }
6308
6309 /* Check if we went past the reported size of IA-NA data. */
6310 if (index != option_length)
6311 {
6312
6313 /* Yes return an error status. */
6314 return NX_DHCPV6_INVALID_IANA_DATA;
6315 }
6316
6317 return NX_SUCCESS;
6318 }
6319
6320
6321 /**************************************************************************/
6322 /* */
6323 /* FUNCTION RELEASE */
6324 /* */
6325 /* _nx_dhcpv6_process_option_request PORTABLE C */
6326 /* 6.1 */
6327 /* AUTHOR */
6328 /* */
6329 /* Yuxin Zhou, Microsoft Corporation */
6330 /* */
6331 /* DESCRIPTION */
6332 /* */
6333 /* This function extracts the option request from the client packet. */
6334 /* */
6335 /* INPUT */
6336 /* */
6337 /* dhcpv6_client_ptr Pointer to DHCPV6 client instance */
6338 /* option_code Option code */
6339 /* option_length Size of option data */
6340 /* option_data Pointer to option data */
6341 /* */
6342 /* OUTPUT */
6343 /* */
6344 /* NX_SUCCESS Successful completion status */
6345 /* */
6346 /* CALLS */
6347 /* */
6348 /* _nx_dhcpv6_server_utility_get_data */
6349 /* Parses data from specified buffer */
6350 /* */
6351 /* CALLED BY */
6352 /* */
6353 /* _nx_dhcpv6_server_extract_packet_information */
6354 /* Extracts DHCPv6 data from packet */
6355 /* */
6356 /* RELEASE HISTORY */
6357 /* */
6358 /* DATE NAME DESCRIPTION */
6359 /* */
6360 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6361 /* 09-30-2020 Yuxin Zhou Modified comment(s), improved */
6362 /* packet length verification, */
6363 /* resulting in version 6.1 */
6364 /* */
6365 /**************************************************************************/
_nx_dhcpv6_process_option_request(NX_DHCPV6_CLIENT * dhcpv6_client_ptr,ULONG option_code,UINT option_length,UCHAR * option_data)6366 UINT _nx_dhcpv6_process_option_request(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, ULONG option_code, UINT option_length, UCHAR *option_data)
6367 {
6368
6369 ULONG data;
6370 UINT i = 0;
6371 UINT index = 0;
6372
6373
6374 /* Set option code and length. */
6375 dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_op_code = (USHORT)option_code;
6376 dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_option_length = (USHORT)option_length;
6377
6378 /* Loop to process requested option. */
6379 while ((index + 2 <= option_length) && (i < NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS))
6380 {
6381
6382 /* Extract the option request which should be the next 2 bytes. */
6383 _nx_dhcpv6_server_utility_get_data(option_data + index, 2, &data);
6384
6385 dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_op_request[i] = (USHORT)data;
6386
6387 /* Update all the length and index counters.*/
6388 index += 2;
6389 i++;
6390 }
6391
6392 return NX_SUCCESS;
6393 }
6394
6395
6396 /**************************************************************************/
6397 /* */
6398 /* FUNCTION RELEASE */
6399 /* */
6400 /* _nx_dhcpv6_process_elapsed_time PORTABLE C */
6401 /* 6.1 */
6402 /* AUTHOR */
6403 /* */
6404 /* Yuxin Zhou, Microsoft Corporation */
6405 /* */
6406 /* DESCRIPTION */
6407 /* */
6408 /* This function extracts the elapsed time option in the client packet.*/
6409 /* */
6410 /* INPUT */
6411 /* */
6412 /* dhcpv6_client_ptr Pointer to DHCPV6 client instance */
6413 /* option_code Option code */
6414 /* option_length Size of option data */
6415 /* option_data Pointer to option data */
6416 /* */
6417 /* OUTPUT */
6418 /* */
6419 /* NX_SUCCESS Successful completion status */
6420 /* NX_DHCPV6_INVALID_OPTION_DATA Elapsed time is missing data */
6421 /* CALLS */
6422 /* */
6423 /* _nx_dhcpv6_server_utility_get_data */
6424 /* Parses data from specified buffer */
6425 /* */
6426 /* CALLED BY */
6427 /* */
6428 /* _nx_dhcpv6_server_extract_packet_information */
6429 /* Extracts DHCPv6 data from packet */
6430 /* */
6431 /* RELEASE HISTORY */
6432 /* */
6433 /* DATE NAME DESCRIPTION */
6434 /* */
6435 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6436 /* 09-30-2020 Yuxin Zhou Modified comment(s), improved */
6437 /* packet length verification, */
6438 /* resulting in version 6.1 */
6439 /* */
6440 /**************************************************************************/
_nx_dhcpv6_process_elapsed_time(NX_DHCPV6_CLIENT * dhcpv6_client_ptr,ULONG option_code,UINT option_length,UCHAR * option_data)6441 UINT _nx_dhcpv6_process_elapsed_time(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, ULONG option_code, UINT option_length, UCHAR *option_data)
6442 {
6443
6444 ULONG data;
6445
6446
6447 /* Set option code and length. */
6448 dhcpv6_client_ptr -> nx_dhcpv6_elapsed_time.nx_op_code = (USHORT)option_code;
6449 dhcpv6_client_ptr -> nx_dhcpv6_elapsed_time.nx_option_length = (USHORT)option_length;
6450
6451 /* Check option length for elapsed-time. */
6452 if (option_length != 2)
6453 {
6454 return(NX_DHCPV6_INVALID_OPTION_DATA);
6455 }
6456
6457 /* Extract the elapsed session time which should be the next 2 bytes. */
6458 _nx_dhcpv6_server_utility_get_data(option_data, 2, &data);
6459 dhcpv6_client_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = (USHORT)data;
6460
6461 return NX_SUCCESS;
6462 }
6463
6464
6465 /**************************************************************************/
6466 /* */
6467 /* FUNCTION RELEASE */
6468 /* */
6469 /* _nx_dhcpv6_server_process_ia PORTABLE C */
6470 /* 6.3.0 */
6471 /* AUTHOR */
6472 /* */
6473 /* Yuxin Zhou, Microsoft Corporation */
6474 /* */
6475 /* DESCRIPTION */
6476 /* */
6477 /* This function extracts the IA address option from the client packet.*/
6478 /* */
6479 /* INPUT */
6480 /* */
6481 /* dhcpv6_client_ptr Pointer to DHCPV6 Client instance */
6482 /* option_code Option code */
6483 /* option_length Size of option data */
6484 /* option_data Pointer to option data */
6485 /* process_ia If true, write IA to client record*/
6486 /* */
6487 /* OUTPUT */
6488 /* */
6489 /* NX_SUCCESS Successful completion status */
6490 /* NX_DHCPV6_INVALID_IA_DATA IA option is missing data or */
6491 /* improperly formatted */
6492 /* NX_DHCPV6_INVALID_IA_TIME IA option lifetime data is invalid*/
6493 /* */
6494 /* CALLS */
6495 /* */
6496 /* _nx_dhcpv6_server_utility_get_data */
6497 /* Extract bytes from a DHCPv6 packet*/
6498 /* */
6499 /* CALLED BY */
6500 /* */
6501 /* _nx_dhcpv6_server_process_iana Processes IANA in client request */
6502 /* */
6503 /* RELEASE HISTORY */
6504 /* */
6505 /* DATE NAME DESCRIPTION */
6506 /* */
6507 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6508 /* 09-30-2020 Yuxin Zhou Modified comment(s), improved */
6509 /* packet length verification, */
6510 /* resulting in version 6.1 */
6511 /* 10-31-2023 Haiqing Zhao Modified comment(s), and */
6512 /* improved to ignore valid */
6513 /* lifetime and preferred life */
6514 /* time in client message, */
6515 /* resulting in version 6.3.0 */
6516 /* */
6517 /**************************************************************************/
_nx_dhcpv6_server_process_ia(NX_DHCPV6_CLIENT * dhcpv6_client_ptr,ULONG option_code,UINT option_length,UCHAR * option_data,UINT process_ia)6518 UINT _nx_dhcpv6_server_process_ia(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, ULONG option_code, UINT option_length, UCHAR *option_data, UINT process_ia)
6519 {
6520
6521 UINT k;
6522 ULONG data;
6523
6524
6525 /* Fill in the IA address code and length. Client might already have one on
6526 record, but use the server's data instead. */
6527 if (process_ia)
6528 {
6529 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code = (USHORT)option_code;
6530 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length = (USHORT)option_length;
6531 }
6532
6533 /* Check option length for Ipv6 address (16 bytes), preferred-lifetime (4 bytes) and valid-lifetime (4 bytes). */
6534 if (option_length != 24)
6535 {
6536 return(NX_DHCPV6_INVALID_IA_DATA);
6537 }
6538
6539 /* Process IPv6 address. */
6540 for (k = 0; k < 4; k++)
6541 {
6542
6543 /* Copy each IPv6 address word into the IA address. */
6544 _nx_dhcpv6_server_utility_get_data(option_data + (k * 4), sizeof(ULONG), &data);
6545
6546 if (process_ia)
6547 {
6548 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[k] = data;
6549 }
6550 }
6551
6552 /* Skip 4 bytes preferred lifetime data and 4 bytes valid lifetime data from the client buffer to IA.
6553 This is because in RFC 8415, page 105, it requires that the server MUST ignore any received
6554 preferred-lifetime and valid-lifetime values in a message sent by a client to a server. */
6555
6556 return(NX_SUCCESS);
6557 }
6558
6559
6560 /**************************************************************************/
6561 /* */
6562 /* FUNCTION RELEASE */
6563 /* */
6564 /* _nx_dhcpv6_process_duid PORTABLE C */
6565 /* 6.1 */
6566 /* AUTHOR */
6567 /* */
6568 /* Yuxin Zhou, Microsoft Corporation */
6569 /* */
6570 /* DESCRIPTION */
6571 /* */
6572 /* This function extracts the DUID from the client packet. */
6573 /* */
6574 /* INPUT */
6575 /* */
6576 /* duid_ptr Pointer to DHCPV6 DUID instance */
6577 /* option_code Option code */
6578 /* option_length Size of option data */
6579 /* option_data Pointer to option data */
6580 /* */
6581 /* OUTPUT */
6582 /* */
6583 /* NX_SUCCESS Successful completion status */
6584 /* NX_DHCPV6_INVALID_DUID DUID is missing data or does not */
6585 /* match the DUID on record */
6586 /* CALLS */
6587 /* */
6588 /* _nx_dhcpv6_server_utility_get_data */
6589 /* Parses data from specified buffer */
6590 /* */
6591 /* CALLED BY */
6592 /* */
6593 /* _nx_dhcpv6_server_extract_packet_information */
6594 /* Extracts DHCPv6 data from packet */
6595 /* */
6596 /* RELEASE HISTORY */
6597 /* */
6598 /* DATE NAME DESCRIPTION */
6599 /* */
6600 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6601 /* 09-30-2020 Yuxin Zhou Modified comment(s), improved */
6602 /* packet length verification, */
6603 /* corrected the logic of */
6604 /* processing DUID type, */
6605 /* resulting in version 6.1 */
6606 /* */
6607 /**************************************************************************/
_nx_dhcpv6_process_duid(NX_DHCPV6_SVR_DUID * duid_ptr,ULONG option_code,UINT option_length,UCHAR * option_data)6608 UINT _nx_dhcpv6_process_duid(NX_DHCPV6_SVR_DUID *duid_ptr, ULONG option_code, UINT option_length, UCHAR *option_data)
6609 {
6610
6611 ULONG data;
6612 UINT index = 0;
6613
6614 NX_PARAMETER_NOT_USED(option_code);
6615
6616 /* Check option length for DUID type. */
6617 if (option_length < 2)
6618 {
6619 return(NX_DHCPV6_INVALID_OPTION_DATA);
6620 }
6621
6622 /* Extract the DUID type which should be the next 2 bytes. */
6623 _nx_dhcpv6_server_utility_get_data(option_data + index, 2, &data);
6624 duid_ptr -> nx_duid_type = (USHORT)data;
6625 index += 2;
6626
6627 /* Check the duid type. */
6628 if ((duid_ptr -> nx_duid_type < NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) ||
6629 (duid_ptr -> nx_duid_type > NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY))
6630 {
6631 return(NX_DHCPV6_INVALID_DUID);
6632 }
6633
6634 /* Check if it is a link layer duid. */
6635 if ((duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) ||
6636 (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY))
6637 {
6638
6639 /* Check option length for hardware type. */
6640 if (index + 2 > option_length)
6641 {
6642 return(NX_DHCPV6_INVALID_OPTION_DATA);
6643 }
6644
6645 /* Extract the hardware type which should be the next 2 bytes. */
6646 _nx_dhcpv6_server_utility_get_data(option_data + index, 2, &data);
6647 duid_ptr -> nx_hardware_type = (USHORT)data;
6648 index += 2;
6649
6650 /* IS this a link layer plus time DUID type? */
6651 if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME)
6652 {
6653
6654 /* Check option length for time. */
6655 if (index + 4 > option_length)
6656 {
6657 return(NX_DHCPV6_INVALID_OPTION_DATA);
6658 }
6659
6660 /* Yes; Extract the time which should be the next 4 bytes. */
6661 _nx_dhcpv6_server_utility_get_data(option_data + index, 4, &data);
6662 duid_ptr -> nx_duid_time = data;
6663 index += 4;
6664 }
6665
6666 /* Check option length mac address. */
6667 if (index + 6 > option_length)
6668 {
6669 return(NX_DHCPV6_INVALID_OPTION_DATA);
6670 }
6671
6672 /* Extract the link local address msw which should be the next 2 bytes. */
6673 _nx_dhcpv6_server_utility_get_data(option_data + index, 2, &data);
6674 duid_ptr -> nx_link_layer_address_msw = (USHORT)data;
6675 index += 2;
6676
6677 /* Extract the link local address lsw which should be the next 4 bytes. */
6678 _nx_dhcpv6_server_utility_get_data(option_data + index, 4, &data);
6679 duid_ptr -> nx_link_layer_address_lsw = data;
6680 index += 4;
6681 }
6682 else
6683 {
6684
6685 /* DUID Assigned by Vendor Based on Enterprise Number. */
6686
6687 /* Check option length for enterprise-number. */
6688 if (index + 4 > option_length)
6689 {
6690 return(NX_DHCPV6_INVALID_DUID);
6691 }
6692
6693 /* Extract the enterprise-number which should be the next 4 bytes. */
6694 _nx_dhcpv6_server_utility_get_data(option_data + index, 4, &data);
6695 duid_ptr -> nx_duid_enterprise_number = data;
6696 index += 4;
6697
6698 /* Check the size of identifier. */
6699 if (option_length - 6 <= NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH)
6700 {
6701
6702 /* Set the identifier. */
6703 memcpy(duid_ptr -> nx_duid_private_identifier, option_data + index, option_length - 6); /* Use case of memcpy is verified. */
6704 index = option_length;
6705 }
6706 else
6707 {
6708 return(NX_DHCPV6_INVALID_DUID);
6709 }
6710 }
6711
6712 /* Are we past the end of the buffer, subtracting for the toplevel opcode and
6713 length of the IANA option? */
6714 if (index != option_length)
6715 {
6716
6717 /* Yes, return the error status to reject this packet. */
6718 return NX_DHCPV6_INVALID_OPTION_DATA;
6719 }
6720
6721 return NX_SUCCESS;
6722 }
6723
6724
6725 /**************************************************************************/
6726 /* */
6727 /* FUNCTION RELEASE */
6728 /* */
6729 /* _nx_dhcpv6_check_duids_same PORTABLE C */
6730 /* 6.1 */
6731 /* AUTHOR */
6732 /* */
6733 /* Yuxin Zhou, Microsoft Corporation */
6734 /* */
6735 /* DESCRIPTION */
6736 /* */
6737 /* This function compares the two input DUIDs to match field by field. */
6738 /* if they match, the match status is returned NX_TRUE. */
6739 /* */
6740 /* INPUT */
6741 /* */
6742 /* dhcpv6_duid1_ptr Pointer to first DHCPV6 DUID */
6743 /* dhcpv6_duid1_ptr Pointer to 2nd DHCPV6 DUID */
6744 /* matching Flag indicating if DUIDs match */
6745 /* */
6746 /* OUTPUT */
6747 /* */
6748 /* NX_SUCCESS No errors doing comparison */
6749 /* NX_PTR_ERROR Invalid pointer input */
6750 /* */
6751 /* CALLS */
6752 /* */
6753 /* tx_mutex_get Get server protection mutex */
6754 /* tx_mutex_put Release server protection mutex*/
6755 /* */
6756 /* CALLED BY */
6757 /* */
6758 /* _nx_dhcpv6_listen_for_messages Listen for client requests */
6759 /* _nx_dhcpv6_find_client_record_by_chaddr */
6760 /* Find client in server table */
6761 /* */
6762 /* RELEASE HISTORY */
6763 /* */
6764 /* DATE NAME DESCRIPTION */
6765 /* */
6766 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6767 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6768 /* resulting in version 6.1 */
6769 /* */
6770 /**************************************************************************/
_nx_dhcpv6_check_duids_same(NX_DHCPV6_SVR_DUID * dhcpv6_duid1_ptr,NX_DHCPV6_SVR_DUID * dhcpv6_duid2_ptr,UINT * matching)6771 UINT _nx_dhcpv6_check_duids_same(NX_DHCPV6_SVR_DUID *dhcpv6_duid1_ptr, NX_DHCPV6_SVR_DUID *dhcpv6_duid2_ptr, UINT *matching)
6772 {
6773
6774
6775 /* Check for invalid input. */
6776 if (!dhcpv6_duid1_ptr || !dhcpv6_duid2_ptr || !matching)
6777 {
6778
6779 /* Return invalid input. */
6780 return(NX_PTR_ERROR);
6781 }
6782
6783 /* Initialize result to no match. */
6784 *matching = NX_FALSE;
6785
6786 /* CHeck field by field starting with the ones most likely to miss. */
6787 if (dhcpv6_duid1_ptr -> nx_link_layer_address_msw != dhcpv6_duid2_ptr -> nx_link_layer_address_msw)
6788 {
6789 return NX_SUCCESS;
6790 }
6791 else if (dhcpv6_duid1_ptr -> nx_link_layer_address_lsw != dhcpv6_duid2_ptr -> nx_link_layer_address_lsw)
6792 {
6793 return NX_SUCCESS;
6794 }
6795 else if (dhcpv6_duid1_ptr -> nx_duid_type != dhcpv6_duid2_ptr -> nx_duid_type)
6796 {
6797 return NX_SUCCESS;
6798 }
6799 else if (dhcpv6_duid1_ptr -> nx_hardware_type != dhcpv6_duid2_ptr -> nx_hardware_type)
6800 {
6801 return NX_SUCCESS;
6802 }
6803 else if (dhcpv6_duid1_ptr -> nx_op_code != dhcpv6_duid2_ptr -> nx_op_code)
6804 {
6805 return NX_SUCCESS;
6806 }
6807 else if (dhcpv6_duid1_ptr -> nx_option_length != dhcpv6_duid2_ptr -> nx_option_length)
6808 {
6809 return NX_SUCCESS;
6810 }
6811 else if (dhcpv6_duid1_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME)
6812 {
6813
6814 if (dhcpv6_duid1_ptr -> nx_duid_time != dhcpv6_duid2_ptr -> nx_duid_time)
6815 {
6816 return NX_SUCCESS;
6817 }
6818 }
6819 else if (dhcpv6_duid1_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED)
6820 {
6821
6822 /* First compare the enterprise ID. */
6823 if (dhcpv6_duid1_ptr -> nx_duid_enterprise_number != dhcpv6_duid2_ptr -> nx_duid_enterprise_number)
6824 {
6825 return NX_SUCCESS;
6826 }
6827
6828 /* Then compare the private ID. */
6829 if (memcmp(dhcpv6_duid1_ptr -> nx_duid_private_identifier, dhcpv6_duid2_ptr -> nx_duid_private_identifier,
6830 dhcpv6_duid1_ptr -> nx_option_length - sizeof(ULONG)))
6831 {
6832
6833 /* No match. */
6834 return NX_SUCCESS;
6835 }
6836 }
6837
6838 /* It's match! */
6839 *matching = NX_TRUE;
6840
6841 return(NX_SUCCESS);
6842 }
6843
6844
6845 /**************************************************************************/
6846 /* */
6847 /* FUNCTION RELEASE */
6848 /* */
6849 /* _nx_dhcpv6_add_duid PORTABLE C */
6850 /* 6.1 */
6851 /* AUTHOR */
6852 /* */
6853 /* Yuxin Zhou, Microsoft Corporation */
6854 /* */
6855 /* DESCRIPTION */
6856 /* */
6857 /* This function adds a DHCPv6 DUID to the server response packet */
6858 /* based on the input DUID and the DUID type (client or server). */
6859 /* */
6860 /* INPUT */
6861 /* */
6862 /* dhcpv6_server_ptr Pointer to DHCPV6 server instance */
6863 /* dhcpv6_duid_ptr Pointer to DHCPV6 DUID instance */
6864 /* buffer Pointer to packet buffer */
6865 /* index Location where to add DUID */
6866 /* duid_type Indicate client or serve DUID */
6867 /* */
6868 /* OUTPUT */
6869 /* */
6870 /* NX_SUCCESS Successful completion status */
6871 /* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */
6872 /* Packet buffer too small for DUID */
6873 /* CALLS */
6874 /* */
6875 /* memset Clears specified area of memory */
6876 /* memcpy Copies specified area of memory */
6877 /* */
6878 /* CALLED BY */
6879 /* */
6880 /* _nx_dhcpv6_send_request Compiles and sends the Server */
6881 /* DHCPv6 response */
6882 /* */
6883 /* RELEASE HISTORY */
6884 /* */
6885 /* DATE NAME DESCRIPTION */
6886 /* */
6887 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6888 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
6889 /* verified memcpy use cases, */
6890 /* resulting in version 6.1 */
6891 /* */
6892 /**************************************************************************/
_nx_dhcpv6_add_duid(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_SVR_DUID * dhcpv6_duid_ptr,UCHAR * buffer_ptr,UINT * index,UINT duid_type)6893 UINT _nx_dhcpv6_add_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SVR_DUID *dhcpv6_duid_ptr, UCHAR *buffer_ptr, UINT *index, UINT duid_type)
6894 {
6895
6896 ULONG message_word;
6897 UINT available_payload;
6898
6899 NX_PARAMETER_NOT_USED(duid_type);
6900
6901 /* Clear memory to make the message header. */
6902 memset(&message_word, 0, sizeof(ULONG));
6903
6904 /* Compile the header from the DUID. */
6905 message_word = (ULONG)(dhcpv6_duid_ptr -> nx_op_code << 16);
6906 message_word |= (dhcpv6_duid_ptr -> nx_option_length);
6907
6908 /* Compute the available payload in the packet buffer. */
6909 available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size -
6910 NX_IPv6_UDP_PACKET - *index;
6911
6912 /* Check if the DUID will fit in the packet buffer. */
6913 if (available_payload < (UINT)(dhcpv6_duid_ptr -> nx_option_length + 4))
6914 {
6915
6916 /* Hmmm... not enough! Can't do it. */
6917 return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD;
6918 }
6919
6920 /* Adjust for endianness. */
6921 NX_CHANGE_ULONG_ENDIAN(message_word);
6922
6923 /* Copy first half of the DUID option to packet buffer. */
6924 memcpy(buffer_ptr + *index, &message_word, sizeof(UINT)); /* Use case of memcpy is verified. */
6925 *index += (ULONG)sizeof(UINT);
6926
6927 memset(&message_word, 0, sizeof(ULONG));
6928
6929 /* Set up the rest of the Client DUID header. */
6930 message_word = (ULONG)(dhcpv6_duid_ptr -> nx_duid_type << 16);
6931 message_word |= dhcpv6_duid_ptr -> nx_hardware_type;
6932
6933 /* Adjust for endianness. */
6934 NX_CHANGE_ULONG_ENDIAN(message_word);
6935
6936 /* Set up the DUID option. */
6937 memcpy(buffer_ptr + *index, &message_word, sizeof(UINT)); /* Use case of memcpy is verified. */
6938 *index += (ULONG)sizeof(UINT);
6939
6940 /* Adjust for endianness. */
6941 NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_duid_time);
6942 NX_CHANGE_USHORT_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_msw);
6943 NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_lsw);
6944
6945 /* Include the 'time' field if this is a Link layer time DUID type. */
6946 if (dhcpv6_duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME)
6947 {
6948
6949 memcpy(buffer_ptr + *index, &(dhcpv6_duid_ptr -> nx_duid_time), sizeof(ULONG)); /* Use case of memcpy is verified. */
6950 *index += (ULONG)sizeof(ULONG);
6951 }
6952
6953 /* Copy the rest of the DUID header. */
6954 memcpy(buffer_ptr + *index, &(dhcpv6_duid_ptr -> nx_link_layer_address_msw), sizeof(USHORT)); /* Use case of memcpy is verified. */
6955 *index += (ULONG)sizeof(USHORT);
6956
6957 memcpy(buffer_ptr + *index, &(dhcpv6_duid_ptr -> nx_link_layer_address_lsw), sizeof(ULONG)); /* Use case of memcpy is verified. */
6958 *index += (ULONG)sizeof(ULONG);
6959
6960 /* Swap bytes back to original endianness. */
6961 NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_lsw);
6962 NX_CHANGE_USHORT_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_msw);
6963 NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_duid_time);
6964
6965 return NX_SUCCESS;
6966 }
6967
6968
6969 /**************************************************************************/
6970 /* */
6971 /* FUNCTION RELEASE */
6972 /* */
6973 /* _nx_dhcpv6_server_add_iana PORTABLE C */
6974 /* 6.1 */
6975 /* AUTHOR */
6976 /* */
6977 /* Yuxin Zhou, Microsoft Corporation */
6978 /* */
6979 /* DESCRIPTION */
6980 /* */
6981 /* This function adds the IANA option to the server response packet */
6982 /* using the Client IANA on record. It will also add any 'nested' */
6983 /* options such as the Client IA(s) and IANA status option. */
6984 /* */
6985 /* INPUT */
6986 /* */
6987 /* dhcpv6_server_ptr Pointer to DHCPV6 server instance */
6988 /* dhcpv6_client_ptr Pointer to DHCPV6 client instance */
6989 /* buffer_ptr Pointer to response packet buffer */
6990 /* index Location into buffer to write data*/
6991 /* */
6992 /* OUTPUT */
6993 /* */
6994 /* status Actual completion status */
6995 /* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */
6996 /* Buffer too small for IANA option */
6997 /* CALLS */
6998 /* */
6999 /* _nx_dhcpv6_add_ia Adds the IA option to buffer */
7000 /* memset Clears specified area of memory */
7001 /* memcpy Copies specified area of memory */
7002 /* */
7003 /* CALLED BY */
7004 /* */
7005 /* _nx_dhcpv6_send_request Sends server DHCPv6 response */
7006 /* */
7007 /* RELEASE HISTORY */
7008 /* */
7009 /* DATE NAME DESCRIPTION */
7010 /* */
7011 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
7012 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
7013 /* verified memcpy use cases, */
7014 /* resulting in version 6.1 */
7015 /* */
7016 /**************************************************************************/
_nx_dhcpv6_server_add_iana(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_CLIENT * dhcpv6_client_ptr,UCHAR * buffer_ptr,UINT * index)7017 UINT _nx_dhcpv6_server_add_iana(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index)
7018 {
7019
7020 UINT status;
7021 UINT add_ia;
7022 UINT temp;
7023 UINT temp_index;
7024 ULONG message_word;
7025 UINT available_payload;
7026 NX_DHCPV6_SERVER_IA_NA *iana_ptr;
7027
7028
7029 /* Initialize the completion status variable. */
7030 status = NX_SUCCESS;
7031
7032 /* Compute the available payload in the packet buffer. */
7033 available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size -
7034 NX_IPv6_UDP_PACKET - *index;
7035
7036 iana_ptr = &dhcpv6_client_ptr -> nx_dhcpv6_iana;
7037
7038 /* Check if the client IANA will fit in the packet buffer. */
7039 if (available_payload < (UINT)(iana_ptr -> nx_option_length + 4))
7040 {
7041
7042 /* Hmmm... not enough! Can't do it. */
7043 return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD;
7044 }
7045
7046 /* For release or decline messages, or a server status indicating no IP address can be
7047 assigned yet, set the IANA IP lease times to expired. */
7048 if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) ||
7049 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) ||
7050 (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code != NX_DHCPV6_STATUS_SUCCESS))
7051 {
7052
7053 iana_ptr -> nx_T1 = 0;
7054 iana_ptr -> nx_T2 = 0;
7055
7056 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0;
7057 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0;
7058 }
7059
7060 /* Clear memory to make the first word of the IA-NA header. */
7061 memset(&message_word, 0, sizeof(ULONG));
7062
7063 /* Save this location in the buffer. */
7064 temp_index = *index;
7065
7066 /* Write the IANA opcode and data length into one word. */
7067 message_word = (ULONG)((iana_ptr -> nx_op_code) << 16);
7068
7069 /* Reset the IANA length to just the IANA option fields, (not IA or status options). */
7070 iana_ptr -> nx_option_length = 3 * sizeof(ULONG);
7071
7072 message_word |= iana_ptr -> nx_option_length;
7073
7074 /* Adjust for endianness. */
7075 NX_CHANGE_ULONG_ENDIAN(message_word);
7076
7077 /* Copy the word into the packet buffer going to the server. */
7078 memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); /* Use case of memcpy is verified. */
7079
7080 /* Update the buffer pointer. */
7081 *index += (ULONG)sizeof(ULONG);
7082
7083 /* Adjust for endianness. */
7084 NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_IA_NA_id);
7085 NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T1);
7086 NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T2);
7087
7088 memcpy(buffer_ptr + *index, &(iana_ptr -> nx_IA_NA_id), sizeof(ULONG)); /* Use case of memcpy is verified. */
7089 *index += (ULONG)sizeof(ULONG);
7090
7091 memcpy(buffer_ptr + *index, &(iana_ptr -> nx_T1), sizeof(ULONG)); /* Use case of memcpy is verified. */
7092 *index += (ULONG)sizeof(ULONG);
7093
7094 memcpy(buffer_ptr + *index, &(iana_ptr -> nx_T2), sizeof(ULONG)); /* Use case of memcpy is verified. */
7095 *index += (ULONG)sizeof(ULONG);
7096
7097 /* Swap bytes back. */
7098 NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_IA_NA_id);
7099 NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T1);
7100 NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T2);
7101
7102 /* Determine if we include an IA address option. This requires a successful IANA status
7103 and applies only if the client is requesting or confirming an address including renew/rebinding one. */
7104 add_ia = NX_FALSE;
7105
7106 /* We include an IA if we intend to assign or confirm an IP address. */
7107 if (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code == NX_DHCPV6_STATUS_SUCCESS)
7108 {
7109 if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type >= NX_DHCPV6_MESSAGE_TYPE_SOLICIT) &&
7110 (dhcpv6_client_ptr -> nx_dhcpv6_message_type <= NX_DHCPV6_MESSAGE_TYPE_DECLINE))
7111 {
7112
7113 add_ia = NX_TRUE;
7114 }
7115 }
7116
7117 /* Or if we are confirming the IP address a client is releasing or declining, regardless
7118 if our records show this IP address is bound to this client. Sect 18.2.6-7 RFC 3315. */
7119 if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) ||
7120 (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE))
7121 {
7122 add_ia = NX_TRUE;
7123 }
7124
7125 if (add_ia)
7126 {
7127
7128 temp = *index;
7129
7130 /* Check for a missing IA option (as in the Solicit message did not have one). */
7131 if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code == 0)
7132 {
7133
7134 NX_DHCPV6_ADDRESS_LEASE *client_address_lease;
7135
7136 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code = NX_DHCPV6_OP_IA_ADDRESS;
7137
7138 /* Set the length to include option code, lenght (one word), IPv6 address (4 words), and lifetime data (2 words). */
7139 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length = (2 * sizeof(ULONG))+ (4 * sizeof(ULONG));
7140
7141 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = NX_DHCPV6_DEFAULT_PREFERRED_TIME;
7142
7143 dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime= NX_DHCPV6_DEFAULT_VALID_TIME;
7144
7145 /* Find the Client's tentatively assigned address in the Server IP address list. */
7146 _nx_dhcpv6_find_ip_address(dhcpv6_server_ptr, dhcpv6_client_ptr, &client_address_lease);
7147
7148 if ((status != NX_SUCCESS) || (client_address_lease == NX_NULL))
7149 {
7150
7151 return status;
7152 }
7153
7154 COPY_IPV6_ADDRESS(&client_address_lease -> nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0],
7155 &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0]);
7156 }
7157
7158 status = _nx_dhcpv6_add_ia(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_ia, buffer_ptr, &temp);
7159
7160 if (status != NX_SUCCESS)
7161 {
7162
7163 return status;
7164 }
7165
7166
7167 /* Add the size of the IA(s) to the client IANA. Note that we include the option code
7168 and length field of any nested options. */
7169 iana_ptr -> nx_option_length = (USHORT)(iana_ptr -> nx_option_length + dhcpv6_client_ptr-> nx_dhcpv6_ia.nx_option_length + 4);
7170
7171 /* Update the index into packet buffer from our temporary variable. */
7172 *index = temp;
7173 }
7174
7175 /* Update the IANA status message. */
7176 status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_TRUE);
7177
7178 if (status != NX_SUCCESS)
7179 {
7180
7181 return status;
7182 }
7183
7184 temp = *index;
7185
7186 /* Ok to add one to server reply.*/
7187 status = _nx_dhcpv6_add_iana_status(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_iana_status, buffer_ptr, &temp);
7188
7189 if (status != NX_SUCCESS)
7190 {
7191
7192 return status;
7193 }
7194
7195 /* Update the index into packet buffer from our temporary variable. */
7196 *index = temp;
7197
7198 /* Update the IANA option length with the iana status option size. */
7199 iana_ptr -> nx_option_length = (USHORT)(iana_ptr -> nx_option_length + dhcpv6_client_ptr->nx_dhcpv6_iana_status.nx_option_length + 4);
7200
7201 /* Rewrite the IANA opcode and update the changed IANA data length with the additional IA address option. */
7202 message_word = (ULONG)((iana_ptr -> nx_op_code) << 16);
7203 message_word |= (ULONG)(iana_ptr -> nx_option_length);
7204
7205 /* Adjust for endianness. */
7206 NX_CHANGE_ULONG_ENDIAN(message_word);
7207
7208 /* Copy the updated word into the packet buffer at the saved location. */
7209 memcpy(buffer_ptr + temp_index, &message_word, sizeof(ULONG)); /* Use case of memcpy is verified. */
7210
7211 /* Erase the IANA status message. We will add another message on the next (if any) IANA option for the client. */
7212 status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_FALSE);
7213
7214 return status;
7215 }
7216
7217
7218 /**************************************************************************/
7219 /* */
7220 /* FUNCTION RELEASE */
7221 /* */
7222 /* _nx_dhcpv6_add_ia PORTABLE C */
7223 /* 6.1 */
7224 /* AUTHOR */
7225 /* */
7226 /* Yuxin Zhou, Microsoft Corporation */
7227 /* */
7228 /* DESCRIPTION */
7229 /* */
7230 /* This function adds the IA address option to the server response */
7231 /* packet using the input IA option. */
7232 /* */
7233 /* INPUT */
7234 /* */
7235 /* dhcpv6_server_ptr Pointer to DHCPV6 server instance */
7236 /* dhcpv6_ia_ptr Pointer to IA to add */
7237 /* buffer_ptr Pointer to response packet buffer */
7238 /* index Location into buffer to write data*/
7239 /* */
7240 /* OUTPUT */
7241 /* */
7242 /* NX_SUCCESS Successful completion status */
7243 /* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */
7244 /* Buffer to small for IA option */
7245 /* CALLS */
7246 /* */
7247 /* memset Clears specified area of memory */
7248 /* memcpy Copies specified area of memory */
7249 /* */
7250 /* CALLED BY */
7251 /* */
7252 /* _nx_dhcpv6_server_add_iana Adds the IANA to server response */
7253 /* */
7254 /* RELEASE HISTORY */
7255 /* */
7256 /* DATE NAME DESCRIPTION */
7257 /* */
7258 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
7259 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
7260 /* verified memcpy use cases, */
7261 /* resulting in version 6.1 */
7262 /* */
7263 /**************************************************************************/
_nx_dhcpv6_add_ia(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_SERVER_IA_ADDRESS * dhcpv6_ia_ptr,UCHAR * buffer_ptr,UINT * index)7264 UINT _nx_dhcpv6_add_ia(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SERVER_IA_ADDRESS *dhcpv6_ia_ptr, UCHAR *buffer_ptr, UINT *index)
7265 {
7266
7267 ULONG message_word;
7268 UINT available_payload;
7269
7270
7271 /* Compute the available payload in the packet buffer. */
7272 available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size -
7273 NX_IPv6_UDP_PACKET - *index;
7274
7275 /* Check if the client IA address option will fit in the packet buffer. */
7276 if (available_payload < (UINT)(dhcpv6_ia_ptr -> nx_option_length + 4))
7277 {
7278
7279 /* Hmmm... not enough! Can't do it. */
7280 return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD;
7281 }
7282
7283 /* If the client has created an address option, apply it to the message. */
7284
7285 /* Clear memory to make the first word of the IA-Address header. */
7286 memset(&message_word, 0, sizeof(ULONG));
7287
7288 /* Compile the header from the IA option on the client record. */
7289 message_word = (ULONG)(dhcpv6_ia_ptr -> nx_op_code << 16);
7290 message_word |= dhcpv6_ia_ptr -> nx_option_length;
7291
7292 /* Adjust for endianness. */
7293 NX_CHANGE_ULONG_ENDIAN(message_word);
7294
7295 /* Copy option header into the packet and update the index into the buffer. */
7296 memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); /* Use case of memcpy is verified. */
7297 *index += (ULONG)sizeof(ULONG);
7298
7299 /* Adjust for endianness. */
7300 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[0]);
7301 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[1]);
7302 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[2]);
7303 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[3]);
7304 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_preferred_lifetime);
7305 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_valid_lifetime);
7306
7307 /* Copy the IPv6 address to the packet. */
7308 memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[0]), sizeof(ULONG)); /* Use case of memcpy is verified. */
7309 *index += (ULONG)sizeof(ULONG);
7310
7311 memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[1]), sizeof(ULONG)); /* Use case of memcpy is verified. */
7312 *index += (ULONG)sizeof(ULONG);
7313
7314 memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[2]), sizeof(ULONG)); /* Use case of memcpy is verified. */
7315 *index += (ULONG)sizeof(ULONG);
7316
7317 memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[3]), sizeof(ULONG)); /* Use case of memcpy is verified. */
7318 *index += (ULONG)sizeof(ULONG);
7319
7320 /* Copy the Client's preference for lifetimes to packet. */
7321 memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_preferred_lifetime), sizeof(ULONG)); /* Use case of memcpy is verified. */
7322 *index += (ULONG)sizeof(ULONG);
7323
7324 memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_valid_lifetime), sizeof(ULONG)); /* Use case of memcpy is verified. */
7325 *index += (ULONG)sizeof(ULONG);
7326
7327 /* Swap bytes back. */
7328 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[0]);
7329 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[1]);
7330 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[2]);
7331 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[3]);
7332 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_preferred_lifetime);
7333 NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_valid_lifetime);
7334
7335 return NX_SUCCESS;
7336 }
7337
7338
7339 /**************************************************************************/
7340 /* */
7341 /* FUNCTION RELEASE */
7342 /* */
7343 /* _nx_dhcpv6_add_iana_status PORTABLE C */
7344 /* 6.1 */
7345 /* AUTHOR */
7346 /* */
7347 /* Yuxin Zhou, Microsoft Corporation */
7348 /* */
7349 /* DESCRIPTION */
7350 /* */
7351 /* This function adds the IANA status option to the server response */
7352 /* packet using the input IANA status option. */
7353 /* */
7354 /* INPUT */
7355 /* */
7356 /* dhcpv6_server_ptr Pointer to DHCPV6 server instance */
7357 /* iana_status_ptr Pointer to IANA status option */
7358 /* buffer_ptr Pointer to response packet buffer */
7359 /* index Location into buffer to write data*/
7360 /* */
7361 /* OUTPUT */
7362 /* */
7363 /* NX_SUCCESS Successful completion status */
7364 /* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */
7365 /* Buffer to small for IA option */
7366 /* CALLS */
7367 /* */
7368 /* memset Clears specified area of memory */
7369 /* memcpy Copies specified area of memory */
7370 /* */
7371 /* CALLED BY */
7372 /* */
7373 /* _nx_dhcpv6_server_add_iana Add IANA status to server response*/
7374 /* */
7375 /* RELEASE HISTORY */
7376 /* */
7377 /* DATE NAME DESCRIPTION */
7378 /* */
7379 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
7380 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
7381 /* verified memcpy use cases, */
7382 /* resulting in version 6.1 */
7383 /* */
7384 /**************************************************************************/
_nx_dhcpv6_add_iana_status(NX_DHCPV6_SERVER * dhcpv6_server_ptr,NX_DHCPV6_SERVER_IANA_STATUS * iana_status_ptr,UCHAR * buffer_ptr,UINT * index)7385 UINT _nx_dhcpv6_add_iana_status(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SERVER_IANA_STATUS *iana_status_ptr, UCHAR *buffer_ptr, UINT *index)
7386 {
7387
7388 ULONG message_word;
7389 USHORT message_short;
7390 UINT available_payload;
7391 UINT message_length;
7392
7393
7394 /* Compute the available payload in the packet buffer. */
7395 available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size -
7396 NX_IPv6_UDP_PACKET - *index;
7397
7398 /* Check if the status option will fit in the packet buffer. */
7399 if (available_payload < (UINT)(iana_status_ptr -> nx_option_length + 4))
7400 {
7401
7402 /* Hmmm... not enough! Can't do it. */
7403 return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD;
7404 }
7405
7406 /* Clear memory to make the message header. */
7407 memset(&message_word, 0, sizeof(ULONG));
7408
7409 /* Compile the header for the status option. */
7410 message_word = (ULONG)(iana_status_ptr -> nx_op_code << 16);
7411 message_word |= (iana_status_ptr -> nx_option_length);
7412
7413 /* Adjust for endianness. */
7414 NX_CHANGE_ULONG_ENDIAN(message_word);
7415
7416 /* Copy the word to packet buffer. */
7417 memcpy(buffer_ptr + *index, &message_word, sizeof(UINT)); /* Use case of memcpy is verified. */
7418 *index += (ULONG)sizeof(UINT);
7419
7420 memset(&message_word, 0, sizeof(ULONG));
7421
7422 /* Set up the status option code. */
7423 message_short = iana_status_ptr -> nx_status_code;
7424
7425 /* Adjust for endianness. */
7426 NX_CHANGE_USHORT_ENDIAN(message_short);
7427
7428 /* Set up the DUID option. */
7429 memcpy(buffer_ptr + *index, &message_short, sizeof(USHORT)); /* Use case of memcpy is verified. */
7430 *index += (ULONG)sizeof(USHORT);
7431
7432 message_length = iana_status_ptr -> nx_option_length - (ULONG)(sizeof(USHORT));
7433 memcpy(buffer_ptr + *index, &iana_status_ptr -> nx_status_message[0], message_length); /* Use case of memcpy is verified. */
7434
7435 *index += message_length;
7436
7437 /* No need to swap the last byte. */
7438 return NX_SUCCESS;
7439 }
7440 #endif /* FEATURE_NX_IPV6 */
7441