1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** NetX Component */
17 /** */
18 /** Dynamic Host Configuration Protocol (DHCP) Server */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define NX_DHCP_SERVER_SOURCE_CODE
24
25
26 /* Force error checking to be disabled in this module */
27
28 #ifndef NX_DISABLE_ERROR_CHECKING
29 #define NX_DISABLE_ERROR_CHECKING
30 #endif
31
32 /* Include necessary system files. */
33
34 #include "nx_api.h"
35 #ifndef NX_DISABLE_IPV4
36 #include "nx_ip.h"
37 #include "nx_udp.h"
38 #include "nxd_dhcp_server.h"
39 #include "tx_timer.h"
40 #include "nx_packet.h"
41 #include "nx_system.h"
42
43 /* Bring in externs for caller checking code. */
44
45 NX_CALLER_CHECKING_EXTERNS
46
47 #ifdef EL_PRINTF_ENABLE
48 #define EL_PRINTF printf
49 #endif
50
51 /* Define the DHCP Internal Function. */
52 static VOID _nx_dhcp_server_thread_entry(ULONG ip_instance);
53 static VOID _nx_dhcp_slow_periodic_timer_entry(ULONG info);
54 static VOID _nx_dhcp_fast_periodic_timer_entry(ULONG info);
55 static UINT _nx_dhcp_server_packet_process(NX_DHCP_SERVER *dhcp_ptr, NX_PACKET *packet_ptr);
56 static UINT _nx_dhcp_respond_to_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr);
57 static UINT _nx_dhcp_server_extract_information(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr, NX_PACKET *packet_ptr, UINT iface_index);
58 static UINT _nx_dhcp_process_option_data(NX_DHCP_CLIENT *dhcp_ptr, CHAR *buffer, UCHAR value, UINT get_option_data, UINT size);
59 static UINT _nx_dhcp_add_option(UCHAR *bootp_message, UINT option, UINT size, ULONG value, UINT *index);
60 static UINT _nx_dhcp_add_requested_option(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, UCHAR *buffer, UINT option, UINT *index);
61 static UINT _nx_dhcp_set_server_options(NX_DHCP_SERVER *dhcp_ptr, CHAR *buffer, UINT buffer_length);
62 static UINT _nx_dhcp_load_server_options(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr, UCHAR *buffer, UINT option_type, UINT *index);
63 static UINT _nx_dhcp_parse_next_option(CHAR **buffer, UINT *digit, UINT length);
64 static UINT _nx_dhcp_server_get_data(UCHAR *data, UINT size, ULONG *value);
65 static VOID _nx_dhcp_server_store_data(UCHAR *data, UINT size, ULONG value);
66 static UINT _nx_dhcp_clear_client_session(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr);
67 static UINT _nx_dhcp_validate_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr);
68 static UINT _nx_dhcp_find_client_record_by_chaddr(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG client_mac_msw, ULONG client_mac_lsw,NX_DHCP_CLIENT **dhcp_client_ptr, UINT add_on);
69 static UINT _nx_dhcp_find_client_record_by_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr, UINT iface_index, ULONG assigned_ip_address);
70 static UINT _nx_dhcp_server_assign_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr);
71 static UINT _nx_dhcp_find_interface_table_ip_address(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG ip_address, NX_DHCP_INTERFACE_IP_ADDRESS **return_interface_address);
72 static UINT _nx_dhcp_update_assignable_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr, ULONG ip_address, UINT assign_status);
73 static UINT _nx_dhcp_find_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT *assigned_to_client);
74 static UINT _nx_dhcp_record_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT lease_time);
75 static UINT _nx_dhcp_clear_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner);
76 static VOID _nx_dhcp_server_socket_receive_notify(NX_UDP_SOCKET *socket_ptr);
77
78
79 /* To enable dhcp server output, define TESTOUTPUT. */
80 /* #define TESTOUTPUT 1 */
81
82 /* To enable packet dump, define PACKET_DUMP. */
83 /* #define PACKET_DUMP 1 */
84
85 #ifdef TESTOUTPUT
86
87 static int add_client = 0;
88
89 /* Define how often to print the server table of current clients.
90 For no output set to zero. For low volume, set to 1;
91 for very high volume, set higher so as not to overwelm the processor. */
92
93 #define TRACE_NTH_CLIENT_PACKET 1
94
95 #endif
96
97
98 /**************************************************************************/
99 /* */
100 /* FUNCTION RELEASE */
101 /* */
102 /* _nxe_dhcp_server_create PORTABLE C */
103 /* 6.1 */
104 /* AUTHOR */
105 /* */
106 /* Yuxin Zhou, Microsoft Corporation */
107 /* */
108 /* DESCRIPTION */
109 /* */
110 /* This function checks for errors in the DHCP create function call. */
111 /* */
112 /* INPUT */
113 /* */
114 /* dhcp_ptr Pointer to DHCP Server */
115 /* ip_ptr Pointer to IP instance */
116 /* stack_ptr Pointer to free memory */
117 /* stack_size Size of DHCP server stack */
118 /* name_ptr DHCP name pointer */
119 /* packet_pool Server packet pool for sending*/
120 /* */
121 /* OUTPUT */
122 /* */
123 /* status Completion status */
124 /* */
125 /* CALLS */
126 /* */
127 /* _nx_dhcp_server_create Actual DHCP create function */
128 /* */
129 /* CALLED BY */
130 /* */
131 /* Application Code */
132 /* */
133 /* RELEASE HISTORY */
134 /* */
135 /* DATE NAME DESCRIPTION */
136 /* */
137 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
138 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
139 /* resulting in version 6.1 */
140 /* */
141 /**************************************************************************/
142
_nxe_dhcp_server_create(NX_DHCP_SERVER * dhcp_ptr,NX_IP * ip_ptr,VOID * stack_ptr,ULONG stack_size,CHAR * name_ptr,NX_PACKET_POOL * packet_pool)143 UINT _nxe_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size,
144 CHAR *name_ptr, NX_PACKET_POOL *packet_pool)
145 {
146
147 UINT status;
148
149
150 /* Check for pointer invalid input. */
151 if ((dhcp_ptr == NX_NULL) || (packet_pool == NX_NULL) ||(stack_ptr == NX_NULL) ||(ip_ptr == NX_NULL))
152 {
153 return(NX_PTR_ERROR);
154 }
155
156 if (stack_size == 0)
157 {
158 return(NX_DHCP_PARAMETER_ERROR);
159 }
160
161 /* Check for appropriate caller. */
162 NX_INIT_AND_THREADS_CALLER_CHECKING
163
164 /* Call actual DHCP create service. */
165 status = _nx_dhcp_server_create(dhcp_ptr, ip_ptr, stack_ptr, stack_size, name_ptr, packet_pool);
166
167 /* Return status. */
168 return(status);
169 }
170
171
172 /**************************************************************************/
173 /* */
174 /* FUNCTION RELEASE */
175 /* */
176 /* _nx_dhcp_server_create PORTABLE C */
177 /* 6.1 */
178 /* AUTHOR */
179 /* */
180 /* Yuxin Zhou, Microsoft Corporation */
181 /* */
182 /* DESCRIPTION */
183 /* */
184 /* This function initializes the DHCP Server with necessary components.*/
185 /* It creates a packet pool for sending Server DHCP messages and a */
186 /* thread task for the DHCP server operation. It also sets the standard*/
187 /* DHCP options (e.g. lease time etc) for granting IP addresses. */
188 /* */
189 /* INPUT */
190 /* */
191 /* dhcp_ptr Pointer to DHCP Server */
192 /* ip_ptr Pointer to IP instance */
193 /* stack_ptr Pointer to server thread on */
194 /* the stack */
195 /* stack_size Size of DHCP server stack */
196 /* name_ptr DHCP name pointer */
197 /* packet_pool Server packet pool for sending*/
198 /* DHCP replies to client */
199 /* */
200 /* OUTPUT */
201 /* NX_SUCCESS Successful completion status */
202 /* NX_DHCP_INADEQUATE_PACKET_POOL_PAYLOAD */
203 /* Packet payload too small error*/
204 /* NX_DHCP_NO_SERVER_OPTION_LIST Missing option list error */
205 /* */
206 /* status Completion status of socket */
207 /* and thread create calls */
208 /* */
209 /* CALLS */
210 /* */
211 /* nx_udp_socket_create Create the DHCP UDP socket */
212 /* nx_udp_socket_delete Delete the DHCP UDP socket */
213 /* tx_thread_create Create DHCP processing thread */
214 /* */
215 /* CALLED BY */
216 /* */
217 /* Application Code */
218 /* */
219 /* RELEASE HISTORY */
220 /* */
221 /* DATE NAME DESCRIPTION */
222 /* */
223 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
224 /* 09-30-2020 Yuxin Zhou Modified comment(s), improved */
225 /* buffer length verification, */
226 /* resulting in version 6.1 */
227 /* */
228 /**************************************************************************/
_nx_dhcp_server_create(NX_DHCP_SERVER * dhcp_ptr,NX_IP * ip_ptr,VOID * stack_ptr,ULONG stack_size,CHAR * name_ptr,NX_PACKET_POOL * packet_pool_ptr)229 UINT _nx_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size,
230 CHAR *name_ptr, NX_PACKET_POOL *packet_pool_ptr)
231 {
232
233 UINT status;
234 UINT timer_ticks;
235 UINT i, j;
236
237
238 /* Initialize the DHCP control block to zero. */
239 memset((void *) dhcp_ptr, 0, sizeof(NX_DHCP_SERVER));
240
241 /* Check the Server packet pool is at least large enough for a full sized DHCP message as per
242 RFC 2131, plus header data. */
243 if (packet_pool_ptr -> nx_packet_pool_payload_size < NX_DHCP_MINIMUM_PACKET_PAYLOAD)
244 {
245
246 /* Return the error status. */
247 return(NX_DHCP_INADEQUATE_PACKET_POOL_PAYLOAD);
248 }
249
250 /* Set the packet pool pointer. */
251 dhcp_ptr -> nx_dhcp_packet_pool_ptr = packet_pool_ptr;
252
253 /* Save the DHCP name. */
254 dhcp_ptr -> nx_dhcp_name = name_ptr;
255
256 /* Set the DHCP Server attributes. */
257 dhcp_ptr -> nx_dhcp_ip_ptr = ip_ptr;
258
259 /* Loop through all the interface tables and clear table memory. */
260 for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++)
261 {
262
263 /* Clear all the table's IP address entries. */
264 for (j = 0; j < NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE; j++)
265 {
266
267 memset(&dhcp_ptr -> nx_dhcp_interface_table[i].nx_dhcp_ip_address_list[j],
268 0, sizeof(NX_DHCP_INTERFACE_IP_ADDRESS));
269 }
270
271 /* Clear the DHCP interface itself. */
272 memset(&dhcp_ptr -> nx_dhcp_interface_table[i], 0, sizeof(NX_DHCP_INTERFACE_TABLE));
273 }
274
275 /* Loop through the entire client record table. */
276 for (i = 0; i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE; i++)
277 {
278
279 /* Clear the client record. */
280 memset(&dhcp_ptr -> client_records[i], 0, sizeof(NX_DHCP_CLIENT));
281 }
282
283 /* Verify the application has defined a server option list. */
284 if (sizeof(NX_DHCP_SERVER_OPTION_LIST) == 1)
285 {
286
287 /* No, return the error status. */
288 return(NX_DHCP_NO_SERVER_OPTION_LIST);
289 }
290
291 /* Create the list of DHCP options the server can provide for the client. */
292 status = _nx_dhcp_set_server_options(dhcp_ptr, (CHAR *)NX_DHCP_SERVER_OPTION_LIST, sizeof(NX_DHCP_SERVER_OPTION_LIST) - 1);
293
294 /* Was the option list set successful? */
295 if (status != NX_SUCCESS)
296 {
297
298 /* No, return error status. */
299 return(status);
300 }
301
302 /* Update the dhcp structure ID. */
303 dhcp_ptr -> nx_dhcp_id = NX_DHCP_SERVER_ID;
304
305 /* Create the Socket and check the status */
306 status = nx_udp_socket_create(ip_ptr, &(dhcp_ptr -> nx_dhcp_socket), "NetX DHCP Server Socket",
307 NX_DHCP_TYPE_OF_SERVICE, NX_DHCP_FRAGMENT_OPTION, NX_DHCP_TIME_TO_LIVE, NX_DHCP_QUEUE_DEPTH);
308
309 /* Was the socket creation successful? */
310 if (status != NX_SUCCESS)
311 {
312
313 /* No, return error status. */
314 return(status);
315 }
316
317 /* Save the DHCP instance pointer in the socket. */
318 dhcp_ptr -> nx_dhcp_socket.nx_udp_socket_reserved_ptr = (void *) dhcp_ptr;
319
320 /* Set the DHCP request handler for packets received on the DHCP server socket. */
321 status = nx_udp_socket_receive_notify(&(dhcp_ptr -> nx_dhcp_socket), _nx_dhcp_server_socket_receive_notify);
322
323 /* Was the socket receive_notify set successful? */
324 if (status != NX_SUCCESS)
325 {
326
327 /* Delete the UDP socket. */
328 nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
329
330 /* No, return error status. */
331 return status;
332 }
333
334 /* Create the DHCP processing thread. */
335 status = tx_thread_create(&(dhcp_ptr -> nx_dhcp_server_thread), "NetX DHCP Server Thread",
336 _nx_dhcp_server_thread_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr,
337 stack_ptr, stack_size, NX_DHCP_SERVER_THREAD_PRIORITY,
338 NX_DHCP_SERVER_THREAD_PRIORITY, 1, TX_DONT_START);
339
340 NX_THREAD_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_server_thread), dhcp_ptr)
341
342 /* Determine if the thread creation was successful. */
343 if (status != NX_SUCCESS)
344 {
345
346 /* Delete the UDP socket. */
347 nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
348
349 /* No, return error status. */
350 return(status);
351 }
352
353 /* Create the DHCP mutex. */
354 status = tx_mutex_create(&dhcp_ptr -> nx_dhcp_mutex, "DHCP Server Mutex", TX_NO_INHERIT);
355
356 /* Determine if the thread creation was successful. */
357 if (status != NX_SUCCESS)
358 {
359
360 /* Delete the UDP socket. */
361 nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
362
363 /* Delete DHCP thead. */
364 tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread));
365
366 /* No, return error status. */
367 return(status);
368 }
369
370 /* Convert seconds to timer ticks. */
371 timer_ticks = NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL * NX_IP_PERIODIC_RATE;
372
373 /* Create the timer for Client DHCP session. This will keep track of when leases expire
374 and when a client session has timed out. */
375 status = tx_timer_create(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer), "DHCP Server IP Lease Timer",
376 _nx_dhcp_slow_periodic_timer_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr,
377 timer_ticks, timer_ticks, TX_NO_ACTIVATE);
378
379 NX_TIMER_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer), dhcp_ptr)
380
381 /* Convert seconds to timer ticks. */
382 timer_ticks = NX_DHCP_FAST_PERIODIC_TIME_INTERVAL * NX_IP_PERIODIC_RATE;
383
384 /* Create the timer for Client DHCP session. This will keep track of when leases expire
385 and when a client session has timed out. */
386 status += tx_timer_create(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer), "DHCP Server Session Timer",
387 _nx_dhcp_fast_periodic_timer_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr,
388 timer_ticks, timer_ticks, TX_NO_ACTIVATE);
389
390 NX_TIMER_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer), dhcp_ptr)
391
392 /* Check for error. */
393 if (status != NX_SUCCESS)
394 {
395
396 /* Delete the UDP socket. */
397 nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
398
399 /* Delete DHCP thead. */
400 tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread));
401
402 /* Delete ThreadX resources. */
403 tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex));
404
405 /* Delete DHCP timer. */
406 tx_timer_delete(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer));
407 tx_timer_delete(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer));
408
409 /* Return the error status. */
410 return(status);
411 }
412
413 /* Create the DHCP event flag instance. */
414 status = tx_event_flags_create(&dhcp_ptr -> nx_dhcp_server_events, "DHCP Server Events");
415
416 /* Check for error. */
417 if (status != TX_SUCCESS)
418 {
419
420 /* Delete the UDP socket. */
421 nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
422
423 /* Delete DHCP thread. */
424 tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread));
425
426 /* Delete ThreadX resources. */
427 tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex));
428
429 /* Delete DHCP Timer. */
430 tx_timer_delete(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer));
431
432 tx_timer_delete(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer));
433
434 /* Return the error status. */
435 return(status);
436 }
437
438 /* Return a successful status. */
439 return(NX_SUCCESS);
440 }
441
442
443 /**************************************************************************/
444 /* */
445 /* FUNCTION RELEASE */
446 /* */
447 /* _nx_dhcp_fast_periodic_timer_entry PORTABLE C */
448 /* 6.1 */
449 /* AUTHOR */
450 /* */
451 /* Yuxin Zhou, Microsoft Corporation */
452 /* */
453 /* DESCRIPTION */
454 /* */
455 /* This function watches the session timeout on each active client */
456 /* session. WHen it does it clears session data from the client record */
457 /* and resets the client state to INIT. If a iP address had been */
458 /* assigned, it is returned back to the server pool. */
459 /* */
460 /* INPUT */
461 /* */
462 /* info Generic pointer to DHCP server */
463 /* */
464 /* OUTPUT */
465 /* */
466 /* None */
467 /* */
468 /* CALLS */
469 /* */
470 /* tx_event_flags_set Adds a fast periodic event */
471 /* */
472 /* CALLED BY */
473 /* */
474 /* Application code */
475 /* */
476 /* RELEASE HISTORY */
477 /* */
478 /* DATE NAME DESCRIPTION */
479 /* */
480 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
481 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
482 /* resulting in version 6.1 */
483 /* */
484 /**************************************************************************/
_nx_dhcp_fast_periodic_timer_entry(ULONG info)485 static VOID _nx_dhcp_fast_periodic_timer_entry(ULONG info)
486 {
487
488 NX_DHCP_SERVER *dhcp_ptr;
489
490
491 /* Setup DHCP pointer. */
492 NX_TIMER_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP_SERVER, info)
493
494 /* Signal the DHCP Server fast periodic event. */
495 tx_event_flags_set(&(dhcp_ptr -> nx_dhcp_server_events), NX_DHCP_SERVER_FAST_PERIODIC_EVENT, TX_OR);
496
497 return;
498 }
499
500
501 /**************************************************************************/
502 /* */
503 /* FUNCTION RELEASE */
504 /* */
505 /* _nx_dhcp_slow_periodic_timer_entry PORTABLE C */
506 /* 6.1 */
507 /* AUTHOR */
508 /* */
509 /* Yuxin Zhou, Microsoft Corporation */
510 /* */
511 /* DESCRIPTION */
512 /* */
513 /* This function watches lease timeout on assigned IP address in the */
514 /* server database. When one has expired, the address is returned to */
515 /* the available pool and the Client is reset to the INIT state. */
516 /* */
517 /* INPUT */
518 /* */
519 /* info Generic pointer to DHCP server */
520 /* */
521 /* OUTPUT */
522 /* */
523 /* None */
524 /* */
525 /* CALLS */
526 /* */
527 /* tx_event_flags_set Adds a slow periodic event */
528 /* */
529 /* CALLED BY */
530 /* */
531 /* ThreadX system timer thread */
532 /* */
533 /* RELEASE HISTORY */
534 /* */
535 /* DATE NAME DESCRIPTION */
536 /* */
537 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
538 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
539 /* resulting in version 6.1 */
540 /* */
541 /**************************************************************************/
_nx_dhcp_slow_periodic_timer_entry(ULONG info)542 static VOID _nx_dhcp_slow_periodic_timer_entry(ULONG info)
543 {
544
545 NX_DHCP_SERVER *dhcp_ptr;
546
547
548 /* Setup DHCP pointer. */
549 NX_TIMER_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP_SERVER, info)
550
551 /* Signal the DHCP Server slow periodic event. */
552 tx_event_flags_set(&(dhcp_ptr -> nx_dhcp_server_events), NX_DHCP_SERVER_SLOW_PERIODIC_EVENT, TX_OR);
553
554 return;
555 }
556
557
558 /**************************************************************************/
559 /* */
560 /* FUNCTION RELEASE */
561 /* */
562 /* _nx_dhcp_server_socket_receive_notify PORTABLE C */
563 /* 6.1 */
564 /* AUTHOR */
565 /* */
566 /* Yuxin Zhou, Microsoft Corporation */
567 /* */
568 /* DESCRIPTION */
569 /* */
570 /* This function is notified by NetX Duo when a packet arrives in the */
571 /* server socket. It sets a flag which the DHCP server thread */
572 /* detect so it will know to process the incoming packet . */
573 /* */
574 /* INPUT */
575 /* */
576 /* socket_ptr Pointer to Server Socket */
577 /* */
578 /* OUTPUT */
579 /* */
580 /* None */
581 /* */
582 /* CALLS */
583 /* */
584 /* None */
585 /* tx_event_flags_set Adds a packet receive event */
586 /* CALLED BY */
587 /* */
588 /* Threads */
589 /* */
590 /* RELEASE HISTORY */
591 /* */
592 /* DATE NAME DESCRIPTION */
593 /* */
594 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
595 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
596 /* resulting in version 6.1 */
597 /* */
598 /**************************************************************************/
_nx_dhcp_server_socket_receive_notify(NX_UDP_SOCKET * socket_ptr)599 VOID _nx_dhcp_server_socket_receive_notify(NX_UDP_SOCKET *socket_ptr)
600 {
601
602 NX_DHCP_SERVER *dhcp_server_ptr;
603
604
605 /* Get a pointer to the DHCP server. */
606 dhcp_server_ptr = (NX_DHCP_SERVER *) socket_ptr -> nx_udp_socket_reserved_ptr;
607
608 /* Signal the DHCP Server it has a UDP packet on its socket receive queue. */
609 tx_event_flags_set(&(dhcp_server_ptr -> nx_dhcp_server_events), NX_DHCP_SERVER_RECEIVE_EVENT, TX_OR);
610
611 return;
612 }
613
614
615 /**************************************************************************/
616 /* */
617 /* FUNCTION RELEASE */
618 /* */
619 /* _nxe_dhcp_server_delete PORTABLE C */
620 /* 6.1 */
621 /* AUTHOR */
622 /* */
623 /* Yuxin Zhou, Microsoft Corporation */
624 /* */
625 /* DESCRIPTION */
626 /* */
627 /* This function checks for errors in the DHCP delete function call. */
628 /* */
629 /* INPUT */
630 /* */
631 /* dhcp_ptr Pointer to DHCP Server */
632 /* */
633 /* OUTPUT */
634 /* */
635 /* status Completion status */
636 /* */
637 /* CALLS */
638 /* */
639 /* _nx_dhcp_server_delete Actual DHCP delete function */
640 /* */
641 /* CALLED BY */
642 /* */
643 /* Application Code */
644 /* */
645 /* RELEASE HISTORY */
646 /* */
647 /* DATE NAME DESCRIPTION */
648 /* */
649 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
650 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
651 /* resulting in version 6.1 */
652 /* */
653 /**************************************************************************/
_nxe_dhcp_server_delete(NX_DHCP_SERVER * dhcp_ptr)654 UINT _nxe_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr)
655 {
656
657 UINT status;
658
659
660 /* Check for invalid input pointers. */
661 if (dhcp_ptr == NX_NULL)
662 return(NX_PTR_ERROR);
663
664 if (dhcp_ptr -> nx_dhcp_id != NX_DHCP_SERVER_ID)
665 {
666 return(NX_DHCP_PARAMETER_ERROR);
667 }
668
669 /* Check for appropriate caller. */
670 NX_THREADS_ONLY_CALLER_CHECKING
671
672 /* Call actual DHCP delete service. */
673 status = _nx_dhcp_server_delete(dhcp_ptr);
674
675 /* Return status. */
676 return(status);
677 }
678
679
680 /**************************************************************************/
681 /* */
682 /* FUNCTION RELEASE */
683 /* */
684 /* _nx_dhcp_server_delete PORTABLE C */
685 /* 6.1 */
686 /* AUTHOR */
687 /* */
688 /* Yuxin Zhou, Microsoft Corporation */
689 /* */
690 /* DESCRIPTION */
691 /* */
692 /* This function deletes the DHCP server and releases all of its */
693 /* resources. */
694 /* */
695 /* INPUT */
696 /* */
697 /* dhcp_ptr Pointer to DHCP Server */
698 /* */
699 /* OUTPUT */
700 /* */
701 /* status Completion status */
702 /* */
703 /* CALLS */
704 /* */
705 /* nx_udp_socket_unbind Free the UDP socket port */
706 /* nx_udp_socket_delete Delete the DHCP UDP socket */
707 /* tx_thread_terminate Terminate DHCP thread */
708 /* tx_thread_terminate Terminate DHCP thread */
709 /* tx_thread_delete Delete DHCP thread */
710 /* tx_timer_delete Delete DHCP timer */
711 /* */
712 /* CALLED BY */
713 /* */
714 /* Application Code */
715 /* */
716 /* RELEASE HISTORY */
717 /* */
718 /* DATE NAME DESCRIPTION */
719 /* */
720 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
721 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
722 /* resulting in version 6.1 */
723 /* */
724 /**************************************************************************/
_nx_dhcp_server_delete(NX_DHCP_SERVER * dhcp_ptr)725 UINT _nx_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr)
726 {
727
728
729 /* Determine if DHCP is stopped. */
730 if (dhcp_ptr -> nx_dhcp_started != NX_FALSE)
731 {
732
733 /* Stop the DHCP server. */
734 _nx_dhcp_server_stop(dhcp_ptr);
735 }
736
737 /* Delete the UDP socket. */
738 nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
739
740 /* Delete the session ("fast") timer. */
741 tx_timer_delete(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer));
742
743 /* Delete the IP lease ("slow") timer. */
744 tx_timer_delete(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer));
745
746 /* Suspend the DHCP processing thread. */
747 tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_server_thread));
748
749 /* Terminate the DHCP processing thread. */
750 tx_thread_terminate(&(dhcp_ptr -> nx_dhcp_server_thread));
751
752 /* Delete the DHCP processing thread. */
753 tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread));
754
755 /* Delete the mutexes. */
756 tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex));
757
758 /* Delete the flag event. */
759 tx_event_flags_delete(&(dhcp_ptr -> nx_dhcp_server_events));
760
761 /* Clear the dhcp structure ID. */
762 dhcp_ptr -> nx_dhcp_id = 0;
763
764 /* Return a successful status. */
765 return(NX_SUCCESS);
766 }
767
768
769 /**************************************************************************/
770 /* */
771 /* FUNCTION RELEASE */
772 /* */
773 /* _nxe_dhcp_create_server_ip_address_list PORTABLE C */
774 /* 6.1 */
775 /* AUTHOR */
776 /* */
777 /* Yuxin Zhou, Microsoft Corporation */
778 /* */
779 /* DESCRIPTION */
780 /* */
781 /* This function performs error checking for the IP address list create*/
782 /* service. */
783 /* */
784 /* INPUT */
785 /* */
786 /* dhcp_ptr Pointer to DHCP Server */
787 /* iface_index IP interface index to specify the */
788 /* DHCP server interface to use */
789 /* start_ip_address Starting IP address */
790 /* end_ip_address Ending IP address */
791 /* addresses_added Pointer to addresses added counter */
792 /* */
793 /* OUTPUT */
794 /* */
795 /* NX_SUCCESS Successful completion status */
796 /* NX_PTR_ERROR Invalid pointer input */
797 /* */
798 /* CALLS */
799 /* */
800 /* _nx_dhcp_create_server_ip_address_list */
801 /* Actual IP address create service */
802 /* */
803 /* CALLED BY */
804 /* */
805 /* Application code */
806 /* */
807 /* RELEASE HISTORY */
808 /* */
809 /* DATE NAME DESCRIPTION */
810 /* */
811 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
812 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
813 /* resulting in version 6.1 */
814 /* */
815 /**************************************************************************/
_nxe_dhcp_create_server_ip_address_list(NX_DHCP_SERVER * dhcp_ptr,UINT iface_index,ULONG start_ip_address,ULONG end_ip_address,UINT * addresses_added)816 UINT _nxe_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index,
817 ULONG start_ip_address, ULONG end_ip_address, UINT *addresses_added)
818 {
819
820 UINT status;
821
822
823 /* Check for invalid input. */
824 if ((dhcp_ptr == NX_NULL) || (addresses_added == NX_NULL))
825 {
826 return(NX_PTR_ERROR);
827 }
828
829 /* Check for invalid non pointer input. */
830 if ((start_ip_address > end_ip_address) ||
831 (iface_index >= NX_MAX_PHYSICAL_INTERFACES) ||
832 (start_ip_address == NX_DHCP_NO_ADDRESS))
833 {
834
835 return(NX_DHCP_INVALID_IP_ADDRESS);
836 }
837
838 status = _nx_dhcp_create_server_ip_address_list(dhcp_ptr, iface_index, start_ip_address, end_ip_address, addresses_added);
839
840 return(status);
841 }
842
843
844 /**************************************************************************/
845 /* */
846 /* FUNCTION RELEASE */
847 /* */
848 /* _nx_dhcp_create_server_ip_address_list PORTABLE C */
849 /* 6.1 */
850 /* AUTHOR */
851 /* */
852 /* Yuxin Zhou, Microsoft Corporation */
853 /* */
854 /* DESCRIPTION */
855 /* */
856 /* This function creates a list of available IP addresses for DHCP */
857 /* clients on the specified interface. The caller supplies a start and */
858 /* end IP address and all addresses in between are flagged as available.*/
859 /* The start ip address is assumed to be the first entry in the list, */
860 /* not appended to a previously started list. All the IP addresses may */
861 /* not fit in the server interface table; the number actually added is */
862 /* written to the 'addresses added' variable. The caller should check */
863 /* this output. */
864 /* */
865 /* If some addresses within the specified range need to be reserved or */
866 /* statically assigned the host application needs to set their lease to */
867 /* infinity (0xffffffff) and assigned status is set. This function also */
868 /* add the interface subnet, router, dns server for specified index. */
869 /* */
870 /* INPUT */
871 /* */
872 /* dhcp_ptr Pointer to DHCP server */
873 /* iface_index Index specifying server interface*/
874 /* start_ip_address Beginning IP address in list. */
875 /* end_ip_address Ending IP address in list. */
876 /* addresses_added Number of addresses added to list*/
877 /* */
878 /* OUTPUT */
879 /* */
880 /* NX_SUCCESS Successful IP list creation */
881 /* NX_DHCP_SERVER_BAD_INTERFACE_INDEX Invalid interface index input */
882 /* NX_DHCP_INVALID_IP_ADDRESS_LIST Invalid IP list parameter input */
883 /* */
884 /* CALLS */
885 /* */
886 /* _nx_dhcp_update_assignable_ip_address */
887 /* Updates interface table entry */
888 /* with IP address status and owner*/
889 /* _nx_dhcp_clear_client_session Clears client record of session */
890 /* data from most recent client */
891 /* */
892 /* CALLED BY */
893 /* */
894 /* Application code */
895 /* */
896 /* RELEASE HISTORY */
897 /* */
898 /* DATE NAME DESCRIPTION */
899 /* */
900 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
901 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
902 /* resulting in version 6.1 */
903 /* */
904 /**************************************************************************/
_nx_dhcp_create_server_ip_address_list(NX_DHCP_SERVER * dhcp_ptr,UINT iface_index,ULONG start_ip_address,ULONG end_ip_address,UINT * addresses_added)905 UINT _nx_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index,
906 ULONG start_ip_address, ULONG end_ip_address,
907 UINT *addresses_added)
908 {
909
910 UINT i;
911 ULONG next_ip_address;
912 NX_IP *ip_ptr;
913 NX_DHCP_INTERFACE_IP_ADDRESS *ip_address_entry_ptr;
914 NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr;
915
916
917 /* Check for an invalid interface index. */
918 if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
919 {
920 return NX_DHCP_SERVER_BAD_INTERFACE_INDEX;
921 }
922
923 /* Obtain DHCP Server mutex protection,. */
924 tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER);
925
926 *addresses_added = 0;
927 next_ip_address = start_ip_address;
928
929 /* Set local pointer to the list being created for convenience. */
930 dhcp_interface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[iface_index];
931
932 /* Fill in the interface table with DHCP attributes for the specified interface. */
933
934 /* Set up a local variable for convenience. */
935 ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr;
936
937 /* Assign the IP interface specified by the IP interface index to the DHCP interface. */
938 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_incoming_interface = &(ip_ptr -> nx_ip_interface[iface_index]);
939
940 /* Set the server ip address based on the specified interface. */
941 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address = ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_address;
942
943 /* Set the dns server, subnet mask, and router (default gateway) for this interface. */
944 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_dns_ip_address = ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_address;
945 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask = ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_network_mask;
946 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_router_ip_address = ip_ptr -> nx_ip_gateway_address;
947
948
949 /* Make sure the start/end address subnet match the interface subnet. */
950 if ((dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & start_ip_address) !=
951 (dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_interface_table_ptr -> nx_dhcp_server_ip_address))
952 {
953
954 /* Release DHCP Server mutex. */
955 tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex);
956
957 return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX);
958 }
959 if ((dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & end_ip_address) !=
960 (dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_interface_table_ptr -> nx_dhcp_server_ip_address))
961 {
962
963 /* Release DHCP Server mutex. */
964 tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex);
965
966 return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX);
967 }
968
969 /* Zero out the list size. */
970 dhcp_interface_table_ptr -> nx_dhcp_address_list_size = 0;
971
972 /* Check for invalid list parameters. */
973 if ((start_ip_address > end_ip_address) || !start_ip_address || !end_ip_address)
974 {
975
976 /* Release DHCP Server mutex. */
977 tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex);
978
979 return(NX_DHCP_INVALID_IP_ADDRESS_LIST);
980 }
981
982 /* Clear out existing entries and start adding IP addresses at the beginning of the list. */
983 i = 0;
984
985 /* Fit as many IP addresses in the specified range as will fit in the table. */
986 while (i < NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE && next_ip_address <= end_ip_address)
987 {
988
989 /* Set local pointer to the next entry for convenience. */
990 ip_address_entry_ptr = &dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i];
991
992 /* Clear existing entry; client identifier and available status
993 must be initialized to NULL and not assigned respectively. */
994 memset(ip_address_entry_ptr, 0, sizeof(NX_DHCP_INTERFACE_IP_ADDRESS));
995
996 /* Add the next IP address to the list. */
997 ip_address_entry_ptr -> nx_assignable_ip_address = next_ip_address;
998
999 /* Increase the list size. */
1000 dhcp_interface_table_ptr -> nx_dhcp_address_list_size++;
1001
1002 next_ip_address++;
1003 i++;
1004 }
1005
1006 /* Set the actual number of available addresses added to the table. */
1007 *addresses_added = dhcp_interface_table_ptr -> nx_dhcp_address_list_size;
1008
1009 /* Release DHCP Server mutex. */
1010 tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex);
1011
1012 return(NX_SUCCESS);
1013 }
1014
1015
1016 /**************************************************************************/
1017 /* */
1018 /* FUNCTION RELEASE */
1019 /* */
1020 /* _nxe_dhcp_set_interface_network_parameters PORTABLE C */
1021 /* 6.1 */
1022 /* AUTHOR */
1023 /* */
1024 /* Yuxin Zhou, Microsoft Corporation */
1025 /* */
1026 /* DESCRIPTION */
1027 /* */
1028 /* This function performs error checking services for the set interface */
1029 /* network parameters service. */
1030 /* */
1031 /* INPUT */
1032 /* */
1033 /* dhcp_ptr Pointer to DHCP server */
1034 /* iface_index Index specifying server interface*/
1035 /* subnet_mask Network mask for DHCP clients */
1036 /* default_gateway_address Router/default gateway for client*/
1037 /* dns_server_address DNS server for DHCP clients */
1038 /* */
1039 /* OUTPUT */
1040 /* */
1041 /* status Actual completion status */
1042 /* NX_PTR_ERROR Invalid interface index input */
1043 /* NX_DHCP_INVALID_NETWORK_PARAMETERS Invalid network parameter input */
1044 /* */
1045 /* CALLS */
1046 /* */
1047 /* _nx_dhcp_update_assignable_ip_address */
1048 /* Updates interface table entry */
1049 /* with IP address status and owner*/
1050 /* _nx_dhcp_clear_client_session Clears client record of session */
1051 /* data from most recent client */
1052 /* */
1053 /* CALLED BY */
1054 /* */
1055 /* Application code */
1056 /* */
1057 /* RELEASE HISTORY */
1058 /* */
1059 /* DATE NAME DESCRIPTION */
1060 /* */
1061 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1062 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1063 /* resulting in version 6.1 */
1064 /* */
1065 /**************************************************************************/
_nxe_dhcp_set_interface_network_parameters(NX_DHCP_SERVER * dhcp_ptr,UINT iface_index,ULONG subnet_mask,ULONG default_gateway_address,ULONG dns_server_address)1066 UINT _nxe_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index,
1067 ULONG subnet_mask, ULONG default_gateway_address,
1068 ULONG dns_server_address)
1069 {
1070 UINT status;
1071
1072 /* Check for invalid pointer input. */
1073 if (dhcp_ptr == NX_NULL)
1074 {
1075 return(NX_PTR_ERROR);
1076 }
1077
1078 /* Check for non pointer input. */
1079 if ((subnet_mask == 0) || (default_gateway_address == 0) || (dns_server_address == 0))
1080 {
1081 return(NX_DHCP_INVALID_NETWORK_PARAMETERS);
1082 }
1083
1084 /* Call the actual service. */
1085 status = _nx_dhcp_set_interface_network_parameters(dhcp_ptr, iface_index,
1086 subnet_mask, default_gateway_address,
1087 dns_server_address);
1088 /* Return completion status. */
1089 return(status);
1090 }
1091
1092
1093 /**************************************************************************/
1094 /* */
1095 /* FUNCTION RELEASE */
1096 /* */
1097 /* _nx_dhcp_set_interface_network_parameters PORTABLE C */
1098 /* 6.1 */
1099 /* AUTHOR */
1100 /* */
1101 /* Yuxin Zhou, Microsoft Corporation */
1102 /* */
1103 /* DESCRIPTION */
1104 /* */
1105 /* This function sets the DHCP server default options for 'network */
1106 /* critical parameters:' gateway, dns server and network mask for the */
1107 /* specified interface. */
1108 /* */
1109 /* INPUT */
1110 /* */
1111 /* dhcp_ptr Pointer to DHCP server */
1112 /* iface_index Index specifying server interface*/
1113 /* subnet_mask Network mask for DHCP clients */
1114 /* default_gateway_address Router/default gateway for client*/
1115 /* dns_server_address DNS server for DHCP clients */
1116 /* */
1117 /* OUTPUT */
1118 /* */
1119 /* NX_SUCCESS Valid parameters received */
1120 /* NX_DHCP_SERVER_BAD_INTERFACE_INDEX Invalid interface index input */
1121 /* NX_DHCP_INVALID_NETWORK_PARAMETERS Invalid network parameter input */
1122 /* */
1123 /* CALLS */
1124 /* */
1125 /* None */
1126 /* */
1127 /* CALLED BY */
1128 /* */
1129 /* Application code */
1130 /* */
1131 /* RELEASE HISTORY */
1132 /* */
1133 /* DATE NAME DESCRIPTION */
1134 /* */
1135 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1136 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1137 /* resulting in version 6.1 */
1138 /* */
1139 /**************************************************************************/
_nx_dhcp_set_interface_network_parameters(NX_DHCP_SERVER * dhcp_ptr,UINT iface_index,ULONG subnet_mask,ULONG default_gateway_address,ULONG dns_server_address)1140 UINT _nx_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index,
1141 ULONG subnet_mask, ULONG default_gateway_address,
1142 ULONG dns_server_address)
1143 {
1144
1145 /* Check for invalid non pointer input. */
1146 if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
1147 {
1148
1149 return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX);
1150 }
1151
1152 /* The default gateway should be on the same network as the dhcp server interface. */
1153 if ((default_gateway_address & subnet_mask) !=
1154 (dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address &
1155 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask))
1156 {
1157 return(NX_DHCP_INVALID_NETWORK_PARAMETERS);
1158 }
1159
1160 /* Obtain DHCP Server mutex protection,. */
1161 tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER);
1162
1163 /* Set the subnet, dns server, and router address for this interface. */
1164 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_dns_ip_address = dns_server_address;
1165
1166 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask = subnet_mask;
1167
1168 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_router_ip_address = default_gateway_address;
1169
1170 /* Release DHCP Server mutex. */
1171 tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex);
1172
1173 return(NX_SUCCESS);
1174 }
1175
1176
1177 /**************************************************************************/
1178 /* */
1179 /* FUNCTION RELEASE */
1180 /* */
1181 /* _nxe_dhcp_server_start PORTABLE C */
1182 /* 6.1 */
1183 /* AUTHOR */
1184 /* */
1185 /* Yuxin Zhou, Microsoft Corporation */
1186 /* */
1187 /* DESCRIPTION */
1188 /* */
1189 /* This function checks for errors in the DHCP start function call. */
1190 /* */
1191 /* INPUT */
1192 /* */
1193 /* dhcp_ptr Pointer to DHCP Server */
1194 /* */
1195 /* OUTPUT */
1196 /* */
1197 /* status Completion status */
1198 /* */
1199 /* CALLS */
1200 /* */
1201 /* _nx_dhcp_start Actual DHCP start function */
1202 /* nx_udp_socket_bind Bind the DHCP UDP socket */
1203 /* */
1204 /* CALLED BY */
1205 /* */
1206 /* Application Code */
1207 /* */
1208 /* RELEASE HISTORY */
1209 /* */
1210 /* DATE NAME DESCRIPTION */
1211 /* */
1212 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1213 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1214 /* resulting in version 6.1 */
1215 /* */
1216 /**************************************************************************/
_nxe_dhcp_server_start(NX_DHCP_SERVER * dhcp_ptr)1217 UINT _nxe_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr)
1218 {
1219
1220 UINT status;
1221
1222
1223 /* Check for invalid input pointer. */
1224 if (dhcp_ptr == NX_NULL)
1225 return(NX_PTR_ERROR);
1226
1227 if (dhcp_ptr -> nx_dhcp_id != NX_DHCP_SERVER_ID)
1228 {
1229 return(NX_DHCP_PARAMETER_ERROR);
1230 }
1231
1232 /* Check for appropriate caller. */
1233 NX_INIT_AND_THREADS_CALLER_CHECKING
1234
1235 /* Call actual DHCP start service. */
1236 status = _nx_dhcp_server_start(dhcp_ptr);
1237
1238 /* Return status. */
1239 return(status);
1240 }
1241
1242
1243 /**************************************************************************/
1244 /* */
1245 /* FUNCTION RELEASE */
1246 /* */
1247 /* _nx_dhcp_server_start PORTABLE C */
1248 /* 6.1 */
1249 /* AUTHOR */
1250 /* */
1251 /* Yuxin Zhou, Microsoft Corporation */
1252 /* */
1253 /* DESCRIPTION */
1254 /* */
1255 /* This function initiates the DHCP processing thread. */
1256 /* */
1257 /* INPUT */
1258 /* */
1259 /* dhcp_ptr Pointer to DHCP Server */
1260 /* */
1261 /* OUTPUT */
1262 /* */
1263 /* status Completion status */
1264 /* */
1265 /* CALLS */
1266 /* */
1267 /* nx_udp_socket_bind Bind DHCP socket */
1268 /* nx_udp_socket_unbind Unbind DHCP socket */
1269 /* tx_thread_resume Initiate DHCP processing */
1270 /* tx_mutex_get Get the DHCP mutex */
1271 /* tx_mutex_put Release the DHCP mutex */
1272 /* */
1273 /* CALLED BY */
1274 /* */
1275 /* Application Code */
1276 /* */
1277 /* RELEASE HISTORY */
1278 /* */
1279 /* DATE NAME DESCRIPTION */
1280 /* */
1281 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1282 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1283 /* resulting in version 6.1 */
1284 /* */
1285 /**************************************************************************/
_nx_dhcp_server_start(NX_DHCP_SERVER * dhcp_ptr)1286 UINT _nx_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr)
1287 {
1288
1289 UINT status;
1290
1291
1292 /* Determine if DHCP has already been started. */
1293 if (dhcp_ptr -> nx_dhcp_started)
1294 {
1295
1296 /* Error DHCP has already been started. */
1297
1298 /* Return completion status. */
1299 return(NX_DHCP_SERVER_ALREADY_STARTED);
1300 }
1301
1302 dhcp_ptr -> nx_dhcp_started = NX_TRUE;
1303
1304 /* Bind the UDP socket to the DHCP Socket port. */
1305 status = nx_udp_socket_bind(&(dhcp_ptr -> nx_dhcp_socket), NX_DHCP_SERVER_UDP_PORT, TX_WAIT_FOREVER);
1306
1307 /* Check status. */
1308 if (status != NX_SUCCESS)
1309 {
1310
1311 /* Error, unbind the DHCP socket. */
1312 nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket));
1313
1314 /* Set status to DHCP error code. */
1315 return(status);
1316 }
1317
1318 /* Start the session ("fast") timer. */
1319 tx_timer_activate(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer));
1320
1321 /* Start the IP lease ("slow") timer. */
1322 tx_timer_activate(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer));
1323
1324 /* Start the DHCP server thread. */
1325 tx_thread_resume(&(dhcp_ptr -> nx_dhcp_server_thread));
1326
1327
1328 /* Return completion status. */
1329 return(NX_SUCCESS);
1330 }
1331
1332
1333 /**************************************************************************/
1334 /* */
1335 /* FUNCTION RELEASE */
1336 /* */
1337 /* _nxe_dhcp_server_stop PORTABLE C */
1338 /* 6.1 */
1339 /* AUTHOR */
1340 /* */
1341 /* Yuxin Zhou, Microsoft Corporation */
1342 /* */
1343 /* DESCRIPTION */
1344 /* */
1345 /* This function checks for errors in the DHCP stop function call. */
1346 /* */
1347 /* INPUT */
1348 /* */
1349 /* dhcp_ptr Pointer to DHCP Server */
1350 /* */
1351 /* OUTPUT */
1352 /* */
1353 /* status Completion status */
1354 /* */
1355 /* CALLS */
1356 /* */
1357 /* _nx_dhcp_stop Actual DHCP stop function */
1358 /* */
1359 /* CALLED BY */
1360 /* */
1361 /* Application Code */
1362 /* */
1363 /* RELEASE HISTORY */
1364 /* */
1365 /* DATE NAME DESCRIPTION */
1366 /* */
1367 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1368 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1369 /* resulting in version 6.1 */
1370 /* */
1371 /**************************************************************************/
_nxe_dhcp_server_stop(NX_DHCP_SERVER * dhcp_ptr)1372 UINT _nxe_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr)
1373 {
1374
1375 UINT status;
1376
1377
1378 /* Check for invalid input pointer. */
1379 if (dhcp_ptr == NX_NULL)
1380 return(NX_PTR_ERROR);
1381
1382 if (dhcp_ptr -> nx_dhcp_id != NX_DHCP_SERVER_ID)
1383 {
1384 return(NX_DHCP_PARAMETER_ERROR);
1385 }
1386
1387 /* Check for appropriate caller. */
1388 NX_THREADS_ONLY_CALLER_CHECKING
1389
1390 /* Call actual DHCP stop service. */
1391 status = _nx_dhcp_server_stop(dhcp_ptr);
1392
1393 /* Return status. */
1394 return(status);
1395 }
1396
1397
1398 /**************************************************************************/
1399 /* */
1400 /* FUNCTION RELEASE */
1401 /* */
1402 /* _nx_dhcp_server_stop PORTABLE C */
1403 /* 6.1 */
1404 /* AUTHOR */
1405 /* */
1406 /* Yuxin Zhou, Microsoft Corporation */
1407 /* */
1408 /* DESCRIPTION */
1409 /* */
1410 /* This function halts the DHCP processing thread. */
1411 /* */
1412 /* INPUT */
1413 /* */
1414 /* dhcp_ptr Pointer to DHCP Server */
1415 /* */
1416 /* OUTPUT */
1417 /* */
1418 /* status Completion status */
1419 /* */
1420 /* CALLS */
1421 /* */
1422 /* nx_udp_socket_unbind Unbind the DHCP UDP socket */
1423 /* tx_thread_preemption_change Change the thread preemption */
1424 /* tx_thread_suspend Suspend DHCP processing */
1425 /* tx_thread_wait_abort Remove any thread suspension */
1426 /* tx_timer_deactivate Deactivate timer */
1427 /* */
1428 /* CALLED BY */
1429 /* */
1430 /* Application Code */
1431 /* */
1432 /* RELEASE HISTORY */
1433 /* */
1434 /* DATE NAME DESCRIPTION */
1435 /* */
1436 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1437 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1438 /* resulting in version 6.1 */
1439 /* */
1440 /**************************************************************************/
_nx_dhcp_server_stop(NX_DHCP_SERVER * dhcp_ptr)1441 UINT _nx_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr)
1442 {
1443
1444 UINT current_preemption;
1445
1446
1447 /* Determine if DHCP is started. */
1448 if (dhcp_ptr -> nx_dhcp_started == NX_FALSE)
1449 {
1450
1451 /* DHCP is not started so it can't be stopped. */
1452 return(NX_DHCP_SERVER_NOT_STARTED);
1453 }
1454
1455 /* Obtain mutex protection, which is to say don't interrupt a DHCP server
1456 if it is processing a packet from a DHCP client. */
1457 tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER);
1458
1459 /* Stop the session ("fast") timer. */
1460 tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer));
1461
1462 /* Stop the IP lease ("slow") timer. */
1463 tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer));
1464
1465 /* Clear the started flag here to ensure other threads can't issue a stop while
1466 this stop is in progress. */
1467 dhcp_ptr -> nx_dhcp_started = NX_FALSE;
1468
1469 /* Disable preemption for critical section. */
1470 tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption);
1471
1472 /* Suspend the DHCP thread. */
1473 tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_server_thread));
1474
1475 /* Unbind the port. */
1476 nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket));
1477
1478 /* Restore preemption. */
1479 tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption);
1480
1481 tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex);
1482
1483
1484 /* Return completion status. */
1485 return(NX_SUCCESS);
1486 }
1487
1488
1489 /**************************************************************************/
1490 /* */
1491 /* FUNCTION RELEASE */
1492 /* */
1493 /* _nx_dhcp_server_thread_entry PORTABLE C */
1494 /* 6.1 */
1495 /* AUTHOR */
1496 /* */
1497 /* Yuxin Zhou, Microsoft Corporation */
1498 /* */
1499 /* DESCRIPTION */
1500 /* */
1501 /* This function is top level server processing thread for the DHCP */
1502 /* service. It listens for and processes client requests in an infinite*/
1503 /* loop. */
1504 /* */
1505 /* Note that the current implementation expects a Client to initiate */
1506 /* a session with DISCOVER message rather than using the option of */
1507 /* skipping to the REQUEST message. */
1508 /* */
1509 /* INPUT */
1510 /* */
1511 /* dhcp_instance Pointer to the DHCP server */
1512 /* */
1513 /* OUTPUT */
1514 /* */
1515 /* status Completion status */
1516 /* */
1517 /* CALLS */
1518 /* */
1519 /* _nx_dhcp_process Main DHCP processing function */
1520 /* */
1521 /* CALLED BY */
1522 /* */
1523 /* ThreadX */
1524 /* */
1525 /* RELEASE HISTORY */
1526 /* */
1527 /* DATE NAME DESCRIPTION */
1528 /* */
1529 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1530 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1531 /* resulting in version 6.1 */
1532 /* */
1533 /**************************************************************************/
_nx_dhcp_server_thread_entry(ULONG info)1534 static VOID _nx_dhcp_server_thread_entry(ULONG info)
1535 {
1536
1537 NX_DHCP_SERVER *dhcp_ptr;
1538 ULONG dhcp_events;
1539 NX_DHCP_INTERFACE_TABLE *iface_table_ptr;
1540 NX_DHCP_INTERFACE_IP_ADDRESS *iface_address_ptr;
1541 NX_DHCP_CLIENT *dhcp_client_ptr;
1542 UINT iface_index, i;
1543 UINT status;
1544 NX_PACKET *packet_ptr;
1545
1546
1547 /* Setup the DHCP pointer. */
1548 NX_THREAD_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP_SERVER, info)
1549
1550 /* Enter while loop. */
1551 while(1)
1552 {
1553
1554 /* Release the DHCP mutex. */
1555 tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
1556
1557 /* Pick up IP event flags. */
1558 tx_event_flags_get(&dhcp_ptr -> nx_dhcp_server_events, NX_DHCP_SERVER_ALL_EVENTS,
1559 TX_OR_CLEAR, &dhcp_events, TX_WAIT_FOREVER);
1560
1561 /* Obtain the DHCP mutex before processing the DHCP event. */
1562 tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
1563
1564 /* Check events. */
1565
1566 /* Packet receive event. */
1567 if (dhcp_events & NX_DHCP_SERVER_RECEIVE_EVENT)
1568 {
1569
1570 /* Loop to receive DHCP message. */
1571 while(1)
1572 {
1573
1574 /* Check for an incoming DHCP packet with non blocking option. */
1575 status = _nx_udp_socket_receive(&dhcp_ptr -> nx_dhcp_socket, &packet_ptr, NX_NO_WAIT);
1576
1577 /* Check for packet receive errors. */
1578 if (status != NX_SUCCESS)
1579 {
1580
1581 #ifdef EL_PRINTF_ENABLE
1582 EL_PRINTF("DHCPserv: Error receiving DHCP packet 0x%x\n", status);
1583 #endif
1584 break;
1585 }
1586
1587 /* Process DHCP packet. */
1588 _nx_dhcp_server_packet_process(dhcp_ptr, packet_ptr);
1589 }
1590 }
1591
1592 /* FAST periodic event. */
1593 if (dhcp_events & NX_DHCP_SERVER_FAST_PERIODIC_EVENT)
1594 {
1595
1596 /* Check the clients in active session with the server. */
1597 for (i = 0; i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE; i++)
1598 {
1599
1600 /* Create a local pointer for convenience. */
1601 dhcp_client_ptr = &dhcp_ptr -> client_records[i];
1602
1603 /* Skip empty records. */
1604 if ((dhcp_client_ptr -> nx_dhcp_client_mac_lsw == 0) && (dhcp_client_ptr -> nx_dhcp_client_mac_msw == 0))
1605 continue;
1606
1607 /* Skip clients not in active session with the Server, static members,
1608 or client in the bound state. */
1609 if (dhcp_client_ptr -> nx_dhcp_session_timeout == TX_WAIT_FOREVER)
1610 continue;
1611 if (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_BOUND)
1612 continue;
1613
1614 /* Skip clients whose session timeout is not set e.g. previous session
1615 failed and no longer configured with this server. */
1616 if (dhcp_client_ptr -> nx_dhcp_session_timeout == 0)
1617 continue;
1618 if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS)
1619 continue;
1620
1621 /* Check how much time is left before decreasing the time remaining on the session timeout. */
1622 if (dhcp_client_ptr -> nx_dhcp_session_timeout >= NX_DHCP_FAST_PERIODIC_TIME_INTERVAL)
1623 {
1624 /* Ok to decrement the full amount. */
1625 dhcp_client_ptr -> nx_dhcp_session_timeout -= NX_DHCP_FAST_PERIODIC_TIME_INTERVAL;
1626 }
1627 else
1628 {
1629
1630 /* Set to zero. Time's up! */
1631 dhcp_client_ptr -> nx_dhcp_session_timeout = 0;
1632 }
1633
1634 /* Has time expired on this session? */
1635 if (dhcp_client_ptr -> nx_dhcp_session_timeout == 0)
1636 {
1637
1638 /* Yes, the client has bailed on the session, intentionally or otherwise. If it wants to
1639 get an IP address it must start again. Reset status to 'INIT'. */
1640 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
1641
1642 #ifdef EL_PRINTF_ENABLE
1643 EL_PRINTF("DHCPserv: client session has timed out. Clear session data\n");
1644 #endif
1645
1646 /* Does the client have an assigned IP address? */
1647 if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address)
1648 {
1649
1650 /* Yes, return it back to the available pool. */
1651 _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr,
1652 dhcp_client_ptr -> nx_dhcp_assigned_ip_address,
1653 NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE);
1654
1655 /* The assigned address must be removed. */
1656 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS;
1657
1658 /* Clear the session data, including any data read from last client DHCP message. */
1659 _nx_dhcp_clear_client_session(dhcp_ptr, dhcp_client_ptr);
1660 }
1661 }
1662 }
1663 }
1664
1665 /* Slow periodic event. */
1666 if (dhcp_events & NX_DHCP_SERVER_SLOW_PERIODIC_EVENT)
1667 {
1668
1669 for (iface_index = 0; iface_index < NX_MAX_PHYSICAL_INTERFACES; iface_index++)
1670 {
1671
1672 /* Set a local pointer for convenience. */
1673 iface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[iface_index];
1674
1675 /* Check the interface addresses in the table for lease expiration. */
1676 for (i = 0; i < iface_table_ptr -> nx_dhcp_address_list_size; i++)
1677 {
1678
1679 iface_address_ptr = &iface_table_ptr -> nx_dhcp_ip_address_list[i];
1680
1681 /* Skip all the entries who are not assigned or assigned indefinately (static). */
1682 if(iface_address_ptr -> assigned == NX_FALSE)
1683 continue;
1684 if(iface_address_ptr -> lease_time == TX_WAIT_FOREVER)
1685 continue;
1686
1687 /* Check how much time is left before decreasing the time remaining on the lease timeout. */
1688 if (iface_address_ptr -> lease_time >= NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL)
1689 {
1690
1691 /* Ok to decrement the full amount. */
1692 iface_address_ptr -> lease_time -= NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL;
1693 }
1694 else
1695 {
1696
1697 /* Set to zero. Time's up! */
1698 iface_address_ptr -> lease_time = 0;
1699 }
1700
1701 /* Has time expired on this lease? */
1702 if (iface_address_ptr -> lease_time == 0)
1703 {
1704
1705 /* Yes, make this address available. */
1706
1707 /* Clear the 'owner' field. */
1708 _nx_dhcp_clear_ip_address_owner(iface_address_ptr);
1709
1710 /* Look up the client in the server database by its assigned address. */
1711 _nx_dhcp_find_client_record_by_ip_address(dhcp_ptr, &dhcp_client_ptr, iface_index,
1712 iface_address_ptr -> nx_assignable_ip_address);
1713
1714 /* Did we find it? */
1715 if (dhcp_client_ptr != NX_NULL)
1716 {
1717
1718 /* Remove the assigned IP address and reset the Client to the INIT state. */
1719 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS;
1720 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
1721
1722 #ifdef EL_PRINTF_ENABLE
1723 EL_PRINTF("DHCPserv: client IP lease expired. Clear client data, release IP address\n");
1724 #endif
1725
1726 /* Clear all session data if there is any for this client. */
1727 _nx_dhcp_clear_client_session(dhcp_ptr, dhcp_client_ptr);
1728
1729 /* No, we should have this client in the server client records table but we don't.
1730 That's all we can do right now. */
1731 }
1732 }
1733 }
1734 }
1735 }
1736 };
1737
1738 /* We only break out of this loop in the event of the server stopping
1739 or a fatal error occurring.*/
1740 }
1741
1742
1743 /**************************************************************************/
1744 /* */
1745 /* FUNCTION RELEASE */
1746 /* */
1747 /* _nx_dhcp_respond_to_client_message PORTABLE C */
1748 /* 6.1 */
1749 /* AUTHOR */
1750 /* */
1751 /* Yuxin Zhou, Microsoft Corporation */
1752 /* */
1753 /* DESCRIPTION */
1754 /* */
1755 /* This function prepares a DHCP message response and sends it back to */
1756 /* the Client. Most of the information is obtained from specified */
1757 /* input or from client session record. */
1758 /* */
1759 /* INPUT */
1760 /* */
1761 /* dhcp_ptr Pointer to DHCP Server */
1762 /* dhcp_client_ptr Pointer to client to respond to*/
1763 /* */
1764 /* OUTPUT */
1765 /* */
1766 /* status Completion status from various*/
1767 /* NetX calls */
1768 /* */
1769 /* CALLS */
1770 /* */
1771 /* nx_packet_allocate Allocate a DHCP packet */
1772 /* nx_packet_release Release DHCP packet */
1773 /* nx_udp_socket_send Send DHCP packet */
1774 /* _nx_dhcp_add_option Add an option to the request */
1775 /* _nx_dhcp_add_requested_option Adds non standard option to */
1776 /* server reply to client */
1777 /* _nx_dhcp_load_server_options Load option data from server */
1778 /* option list */
1779 /* _nx_dhcp_server_store_data Store data into buffer */
1780 /* */
1781 /* CALLED BY */
1782 /* */
1783 /* _nx_dhcp_listen_for_messages Service Client DHCP messages */
1784 /* */
1785 /* RELEASE HISTORY */
1786 /* */
1787 /* DATE NAME DESCRIPTION */
1788 /* */
1789 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1790 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1791 /* resulting in version 6.1 */
1792 /* */
1793 /**************************************************************************/
_nx_dhcp_respond_to_client_message(NX_DHCP_SERVER * dhcp_ptr,NX_DHCP_CLIENT * dhcp_client_ptr)1794 static UINT _nx_dhcp_respond_to_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr)
1795 {
1796
1797 NX_PACKET *packet_ptr;
1798 UCHAR *buffer;
1799 UINT status;
1800 UINT destination_ip_address;
1801 UINT destination_port;
1802 UINT index = 0;
1803
1804
1805 #ifdef EL_PRINTF_ENABLE
1806 /* Set local variables for convenience. */
1807 EL_PRINTF("DHCPserv: respond to client message on interface %d\n", dhcp_client_ptr -> nx_dhcp_client_iface_index);
1808 #endif
1809
1810 /* Allocate a DHCP packet. */
1811 status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &packet_ptr, NX_IPv4_UDP_PACKET, NX_DHCP_PACKET_ALLOCATE_TIMEOUT);
1812
1813 /* Was the packet allocation successful? */
1814 if (status != NX_SUCCESS)
1815 {
1816
1817 /* Return status. */
1818 return(status);
1819 }
1820
1821 /* Setup the packet buffer pointer. */
1822 buffer = packet_ptr -> nx_packet_prepend_ptr;
1823
1824 /* Clear the buffer memory. */
1825 memset((void *) buffer, 0, NX_DHCP_OFFSET_END);
1826
1827 /* Setup the standard DHCP fields. */
1828 buffer[NX_DHCP_OFFSET_OP] = NX_DHCP_OP_REPLY;
1829 buffer[NX_DHCP_OFFSET_HTYPE] = (UCHAR)dhcp_client_ptr -> nx_dhcp_client_hwtype;
1830 buffer[NX_DHCP_OFFSET_HLEN] = (UCHAR)dhcp_client_ptr -> nx_dhcp_client_hwlen;
1831 buffer[NX_DHCP_OFFSET_HOPS] = 0;
1832 buffer[NX_DHCP_OFFSET_BOOT_FILE] = 0;
1833
1834 _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_XID, 4, dhcp_client_ptr -> nx_dhcp_xid);
1835 _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_SECS, 2, 0);
1836 _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_CLIENT_IP, 4, NX_DHCP_NO_ADDRESS);
1837 _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_SERVER_IP, 4, NX_DHCP_NO_ADDRESS);
1838 _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_RELAY_IP, 4, NX_DHCP_NO_ADDRESS);
1839 _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_FLAGS, 1, dhcp_client_ptr -> nx_dhcp_broadcast_flag_set);
1840 _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_CLIENT_HW, 2, dhcp_client_ptr -> nx_dhcp_client_mac_msw);
1841 _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_CLIENT_HW + 2, 4, dhcp_client_ptr -> nx_dhcp_client_mac_lsw);
1842 _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_VENDOR, 4, NX_DHCP_MAGIC_COOKIE);
1843
1844 /* Update the index. */
1845 index = NX_DHCP_OFFSET_OPTIONS;
1846
1847 /* Add the list of options that go out with ALL server messages. */
1848 status = _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_ALL_REPLIES, &index);
1849
1850 /* Unless the server is sending a NACK, there are more options to add for the server reply. */
1851 if (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPNACK)
1852 {
1853
1854 /* Add the list of options that go out with server ACK replies (standard network parameters). */
1855 _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_GENERIC_ACK, &index);
1856
1857 /* Determine if there are any message specific options to add. */
1858 switch (dhcp_client_ptr -> nx_dhcp_message_type)
1859 {
1860
1861 case NX_DHCP_TYPE_DHCPDISCOVER:
1862
1863 /* Are we returning an OFFER to the Client? */
1864 if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPOFFER)
1865 {
1866
1867 _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_YOUR_IP, 4, dhcp_client_ptr -> nx_dhcp_your_ip_address);
1868
1869 /* Add the list of options that go out with server OFFER replies. */
1870 _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_REPLY_TO_OFFER, &index);
1871 }
1872
1873 /* Increment the number of Discovery messages received. */
1874 dhcp_ptr -> nx_dhcp_discoveries_received++;
1875 break;
1876
1877
1878 case NX_DHCP_TYPE_DHCPREQUEST:
1879
1880 /* Are we returning an ACK to the Client? */
1881 if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPACK)
1882 {
1883
1884 _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_YOUR_IP, 4, dhcp_client_ptr -> nx_dhcp_assigned_ip_address);
1885
1886 /* Add the list of options that go out with server ACKs replies. */
1887 _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_REPLY_TO_REQUEST, &index);
1888 }
1889
1890 /* Increment the number of Request messages received. */
1891 dhcp_ptr -> nx_dhcp_requests_received++;
1892 break;
1893
1894 /* Note: DHCP Servers should not reply to NX_DHCP_REPLY_TO_RELEASE or NX_DHCP_REPLY_TO_DECLINE messages. */
1895 case NX_DHCP_TYPE_DHCPRELEASE:
1896 dhcp_ptr -> nx_dhcp_releases_received++;
1897 break;
1898
1899 case NX_DHCP_TYPE_DHCPDECLINE:
1900 dhcp_ptr -> nx_dhcp_declines_received++;
1901 break;
1902
1903 case NX_DHCP_TYPE_DHCPINFORM:
1904
1905 /* At this time the server sends just standard network parameters to INFORM requests.
1906 so no additional options to add. */
1907
1908 /* Increment the number of Inform messages received. */
1909 dhcp_ptr -> nx_dhcp_informs_received++;
1910 break;
1911
1912 /* No other DHCP messages are supported by NetX DHCP Server at this time. */
1913 default:
1914 break;
1915 }
1916
1917 /* Determine which of the remaining client requested options the server has information for. */
1918 _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_REQUESTED_BY_CLIENT, &index);
1919 }
1920
1921 /* Setup the packet pointers. */
1922 /* Added the END option. */
1923 *(buffer + index) = NX_DHCP_SERVER_OPTION_END;
1924 index ++;
1925
1926 /* Check the option length. */
1927 if (index > NX_DHCP_OFFSET_END)
1928 {
1929 packet_ptr -> nx_packet_length = index;
1930 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index;
1931 }
1932 else
1933 {
1934 packet_ptr -> nx_packet_length = NX_DHCP_OFFSET_END;
1935 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_END;
1936 }
1937
1938 /* DHCP Server set the correct destination address and port to send resposne. RFC2131, Section4.1, Page23.
1939 1. If the 'giaddr' field in a DHCP message from a client is non-zero, the server sends any return messages to the 'DHCP server' port on the
1940 BOOTP relay agent whose address appears in 'giaddr'.
1941 2. If the 'giaddr'field is zero and the 'ciaddr' field is nonzero, then the server unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'.
1942 3. If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is set, then the server broadcasts DHCPOFFER and DHCPACK messages to 0xffffffff.
1943 4. If the broadcast bit is not set and 'giaddr' is zero and 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK messages to the client's hardware address and 'yiaddr' address.
1944 5. In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK messages to 0xffffffff. */
1945
1946 /* Check the 'giaddr' field. */
1947 if (dhcp_client_ptr -> nx_dhcp_relay_ip_address)
1948 {
1949
1950 /* Set the destination address and port. */
1951 destination_ip_address = dhcp_client_ptr -> nx_dhcp_relay_ip_address;
1952 destination_port = NX_DHCP_SERVER_UDP_PORT;
1953 }
1954 else
1955 {
1956 /* Check the DHCP response message type. */
1957 if (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPNACK)
1958 {
1959
1960 /* Check the 'ciaddr' field*/
1961 if (dhcp_client_ptr -> nx_dhcp_clientip_address)
1962 {
1963 destination_ip_address = dhcp_client_ptr -> nx_dhcp_clientip_address;
1964 }
1965 /* Check the broadcast bit. */
1966 else if (dhcp_client_ptr -> nx_dhcp_broadcast_flag_set & NX_DHCP_FLAGS_BROADCAST)
1967 {
1968 destination_ip_address = NX_DHCP_BC_ADDRESS;
1969 }
1970 else
1971 {
1972 destination_ip_address = dhcp_client_ptr -> nx_dhcp_your_ip_address;
1973
1974 /* Add the dynamic arp entry. */
1975 status = nx_arp_dynamic_entry_set(dhcp_ptr -> nx_dhcp_ip_ptr, destination_ip_address, dhcp_client_ptr -> nx_dhcp_client_mac_msw, dhcp_client_ptr -> nx_dhcp_client_mac_lsw);
1976
1977 /* Check the status. */
1978 if (status)
1979 {
1980 nx_packet_release(packet_ptr);
1981
1982 return(status);
1983 }
1984 }
1985 }
1986 else
1987 {
1988 destination_ip_address = NX_DHCP_BC_ADDRESS;
1989 }
1990
1991 /* Set the destination port. */
1992 destination_port = NX_DHCP_CLIENT_UDP_PORT;
1993 }
1994
1995 #ifdef EL_PRINTF_ENABLE
1996 EL_PRINTF("DHCPserv: DHCP reply packet destination 0x%x\n", destination_ip_address);
1997 EL_PRINTF("DHCPserv: DHCP reply buffer size (bytes) %d\n", packet_ptr -> nx_packet_length);
1998 EL_PRINTF("DHCPserv: DHCP reply packet payload size (bytes) %d\n\n", packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_payload_size);
1999 #endif
2000
2001 #ifdef PACKET_DUMP
2002 {
2003
2004 ULONG *work_ptr;
2005 ULONG uword;
2006 UINT i = 0;
2007 UINT index = 0;
2008 UINT length;
2009
2010 #ifdef EL_PRINTF_ENABLE
2011 EL_PRINTF("DHCPserv: server reply to client - packet dump:\n");
2012 #endif
2013
2014 work_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr;
2015 length = ((packet_ptr -> nx_packet_length + sizeof(ULONG) - 1)/sizeof(ULONG));
2016
2017 while(i < length)
2018 {
2019 uword = *work_ptr;
2020
2021 if (index == 10)
2022 {
2023
2024 #ifdef EL_PRINTF_ENABLE
2025 EL_PRINTF("\n");
2026 #endif
2027 index = 0;
2028 }
2029
2030 #ifdef EL_PRINTF_ENABLE
2031 EL_PRINTF(" %08x", uword);
2032 #endif
2033 work_ptr++;
2034 index++;
2035 i++;
2036 }
2037 #ifdef EL_PRINTF_ENABLE
2038 EL_PRINTF("\n\n");
2039 #endif
2040 }
2041 #endif /* #ifdef PACKET_DUMP */
2042
2043 /* Send the packet. */
2044 status = nx_udp_socket_interface_send(&(dhcp_ptr -> nx_dhcp_socket), packet_ptr, destination_ip_address, destination_port, dhcp_client_ptr -> nx_dhcp_client_iface_index);
2045
2046 if (status != NX_SUCCESS)
2047 {
2048 nx_packet_release(packet_ptr);
2049 }
2050
2051 /* Return completion status. */
2052 return(status);
2053 }
2054
2055
2056 /**************************************************************************/
2057 /* */
2058 /* FUNCTION RELEASE */
2059 /* */
2060 /* _nx_dhcp_clear_client_session PORTABLE C */
2061 /* 6.1 */
2062 /* AUTHOR */
2063 /* */
2064 /* Yuxin Zhou, Microsoft Corporation */
2065 /* */
2066 /* DESCRIPTION */
2067 /* */
2068 /* This function clears data from the current client session (e.g. read*/
2069 /* from the most recent client message. It does remove anything in the */
2070 /* interface table associated with this client's subnet, nor change the*/
2071 /* client state. */
2072 /* */
2073 /* Permanent client info such as client host name, client mac address */
2074 /* assigned IP address, or lease time is not cleared (left to the */
2075 /* caller). */
2076 /* */
2077 /* INPUT */
2078 /* */
2079 /* dhcp_ptr Pointer to DHCP Server */
2080 /* dhcp_client_ptr Pointer to DHCP Client */
2081 /* */
2082 /* OUTPUT */
2083 /* */
2084 /* NX_SUCCESS Successful outcome */
2085 /* */
2086 /* CALLS */
2087 /* */
2088 /* None */
2089 /* */
2090 /* CALLED BY */
2091 /* */
2092 /* _nx_dhcp_listen_for_messages Handle Client DHCP messages */
2093 /* _nx_dhcp_fast_periodic_timer_entry Session timer entry function */
2094 /* */
2095 /* RELEASE HISTORY */
2096 /* */
2097 /* DATE NAME DESCRIPTION */
2098 /* */
2099 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2100 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2101 /* resulting in version 6.1 */
2102 /* */
2103 /**************************************************************************/
_nx_dhcp_clear_client_session(NX_DHCP_SERVER * dhcp_ptr,NX_DHCP_CLIENT * dhcp_client_ptr)2104 static UINT _nx_dhcp_clear_client_session(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr)
2105 {
2106
2107 UINT i;
2108
2109 NX_PARAMETER_NOT_USED(dhcp_ptr);
2110
2111 dhcp_client_ptr -> nx_dhcp_message_type = 0;
2112 dhcp_client_ptr -> nx_dhcp_response_type_to_client = 0;
2113 dhcp_client_ptr -> nx_dhcp_xid = 0;
2114 dhcp_client_ptr -> nx_dhcp_requested_ip_address = 0x0;
2115 dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0x0;
2116 dhcp_client_ptr -> nx_dhcp_your_ip_address = 0x0;
2117 dhcp_client_ptr -> nx_dhcp_clientip_address = 0x0;
2118 dhcp_client_ptr -> nx_dhcp_server_id = 0x0;
2119 dhcp_client_ptr -> nx_dhcp_clientrec_server_ip = 0x0;
2120 dhcp_client_ptr -> nx_dhcp_broadcast_flag_set = NX_DHCP_FLAGS_BROADCAST;
2121 dhcp_client_ptr -> nx_dhcp_session_timeout = 0;
2122 dhcp_client_ptr -> nx_dhcp_destination_ip_address = 0;
2123 dhcp_client_ptr -> nx_dhcp_source_ip_address = 0;
2124
2125 /* Clear out the option data. */
2126 dhcp_client_ptr -> nx_dhcp_client_option_count = 0;
2127 for (i = 0; i < NX_DHCP_CLIENT_OPTIONS_MAX; i++)
2128 {
2129 dhcp_client_ptr -> nx_dhcp_user_options[0] = 0;
2130 }
2131
2132 return(NX_SUCCESS);
2133 }
2134
2135
2136 /**************************************************************************/
2137 /* */
2138 /* FUNCTION RELEASE */
2139 /* */
2140 /* _nxe_dhcp_clear_client_record PORTABLE C */
2141 /* 6.1 */
2142 /* AUTHOR */
2143 /* */
2144 /* Yuxin Zhou, Microsoft Corporation */
2145 /* */
2146 /* DESCRIPTION */
2147 /* */
2148 /* This function performs error checking for the clear client record */
2149 /* service. */
2150 /* */
2151 /* INPUT */
2152 /* */
2153 /* dhcp_ptr Pointer to DHCP Server */
2154 /* dhcp_client_ptr Pointer to DHCP Client */
2155 /* */
2156 /* OUTPUT */
2157 /* */
2158 /* NX_SUCCESS Successful outcome */
2159 /* */
2160 /* CALLS */
2161 /* */
2162 /* _nx_dhcp_clear_client_record Actual clear client record service */
2163 /* */
2164 /* CALLED BY */
2165 /* */
2166 /* Host Application */
2167 /* */
2168 /* RELEASE HISTORY */
2169 /* */
2170 /* DATE NAME DESCRIPTION */
2171 /* */
2172 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2173 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2174 /* resulting in version 6.1 */
2175 /* */
2176 /**************************************************************************/
_nxe_dhcp_clear_client_record(NX_DHCP_SERVER * dhcp_ptr,NX_DHCP_CLIENT * dhcp_client_ptr)2177 UINT _nxe_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr)
2178 {
2179
2180 UINT status;
2181
2182
2183 /* Check for invalid input. */
2184 if ((dhcp_ptr == NX_NULL) || (dhcp_client_ptr == NX_NULL))
2185 {
2186 return(NX_PTR_ERROR);
2187 }
2188
2189 /* Check for appropriate caller. */
2190 NX_THREADS_ONLY_CALLER_CHECKING
2191
2192 /* Call actual DHCP clear client record service. */
2193 status = _nx_dhcp_clear_client_record(dhcp_ptr, dhcp_client_ptr);
2194
2195 /* Return status. */
2196 return(status);
2197 }
2198
2199
2200 /**************************************************************************/
2201 /* */
2202 /* FUNCTION RELEASE */
2203 /* */
2204 /* _nx_dhcp_clear_client_record PORTABLE C */
2205 /* 6.1 */
2206 /* AUTHOR */
2207 /* */
2208 /* Yuxin Zhou, Microsoft Corporation */
2209 /* */
2210 /* DESCRIPTION */
2211 /* */
2212 /* This function clears the entire client record from the server table.*/
2213 /* It also frees up the client's IP address in the server IP address */
2214 /* table. */
2215 /* */
2216 /* The DHCP server does not use this function, it is strictly for the */
2217 /* host application to remove clients from the table (e.g. to free up */
2218 /* room for new clients by removing old 'stale' client entries no */
2219 /* longer configured with the server. */
2220 /* */
2221 /* INPUT */
2222 /* */
2223 /* dhcp_ptr Pointer to DHCP Server */
2224 /* dhcp_client_ptr Pointer to DHCP Client */
2225 /* */
2226 /* OUTPUT */
2227 /* */
2228 /* NX_SUCCESS Successful outcome */
2229 /* */
2230 /* CALLS */
2231 /* */
2232 /* _nx_dhcp_clear_ip_address_owner Clear IP address owner */
2233 /* */
2234 /* CALLED BY */
2235 /* */
2236 /* Host Application */
2237 /* */
2238 /* RELEASE HISTORY */
2239 /* */
2240 /* DATE NAME DESCRIPTION */
2241 /* */
2242 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2243 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2244 /* resulting in version 6.1 */
2245 /* */
2246 /**************************************************************************/
_nx_dhcp_clear_client_record(NX_DHCP_SERVER * dhcp_ptr,NX_DHCP_CLIENT * dhcp_client_ptr)2247 UINT _nx_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr)
2248 {
2249
2250 UINT i;
2251 NX_DHCP_INTERFACE_TABLE *iface_table_ptr;
2252
2253
2254 if (dhcp_client_ptr == 0x0)
2255 {
2256 /* Benign error. Return success. */
2257 return(NX_SUCCESS);
2258 }
2259
2260 /* Obtain DHCP Server mutex protection,. */
2261 tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER);
2262
2263 /* Set local pointer for convenience. */
2264 iface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[dhcp_client_ptr -> nx_dhcp_client_iface_index];
2265
2266 i = 0;
2267
2268 /* Does the client have an assigned IP address? */
2269 if (iface_table_ptr -> nx_dhcp_ip_address_list[i].nx_assignable_ip_address)
2270 {
2271
2272 /* Yes, We need to free up the Client's assigned IP address in the server database. */
2273 while (i < iface_table_ptr -> nx_dhcp_address_list_size)
2274 {
2275
2276 /* Find the interface table entry by matching IP address. */
2277 if (iface_table_ptr -> nx_dhcp_ip_address_list[i].nx_assignable_ip_address ==
2278 dhcp_client_ptr -> nx_dhcp_assigned_ip_address)
2279 {
2280
2281 /* Clear the owner information. */
2282 _nx_dhcp_clear_ip_address_owner(&(iface_table_ptr -> nx_dhcp_ip_address_list[i]));
2283
2284 /* Address now available for DHCP client. */
2285 break;
2286 }
2287 i++;
2288 }
2289 }
2290
2291 /* Ok to clear the Client record. */
2292 memset(dhcp_client_ptr, 0, sizeof(NX_DHCP_CLIENT));
2293
2294 /* Update the total number of dhcp clients. */
2295 if (dhcp_ptr -> nx_dhcp_number_clients > 0)
2296 {
2297
2298 dhcp_ptr -> nx_dhcp_number_clients--;
2299 }
2300
2301 /* Release DHCP Server mutex. */
2302 tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex);
2303
2304 return(NX_SUCCESS);
2305 }
2306
2307
2308 /**************************************************************************/
2309 /* */
2310 /* FUNCTION RELEASE */
2311 /* */
2312 /* _nx_dhcp_load_server_options PORTABLE C */
2313 /* 6.1 */
2314 /* AUTHOR */
2315 /* */
2316 /* Yuxin Zhou, Microsoft Corporation */
2317 /* */
2318 /* DESCRIPTION */
2319 /* */
2320 /* This function adds the specified options in the server's DHCP option */
2321 /* list to the DHCP server response to the Client message. There is a */
2322 /* required set of options that go out with all server messages, as well */
2323 /* as a standard (user configurable) set of options for all 'ACK' */
2324 /* messages. Lastly, there are certain options that are specific to the */
2325 /* client message request e.g. RENEW vs OFFER etc */
2326 /* */
2327 /* There is no support for responding to specific client options in this */
2328 /* revision. */
2329 /* */
2330 /* INPUT */
2331 /* */
2332 /* dhcp_ptr Pointer to DHCP Server */
2333 /* dhcp_client_ptr Pointer to client session record*/
2334 /* buffer Packet buffer to load options to*/
2335 /* option_type Category of options to load */
2336 /* */
2337 /* OUTPUT */
2338 /* */
2339 /* NX_SUCCESS Successful completion status */
2340 /* */
2341 /* CALLS */
2342 /* */
2343 /* _nx_dhcp_add_option Add option to response (specify */
2344 /* option and data to add)*/
2345 /* _nx_dhcp_add_requested_option Add option to response */
2346 /* (specify option and client */
2347 /* interface) */
2348 /* */
2349 /* CALLED BY */
2350 /* */
2351 /* _nx_dhcp_respond_to_dhcp_message Create and send response back */
2352 /* DHCP Client */
2353 /* */
2354 /* RELEASE HISTORY */
2355 /* */
2356 /* DATE NAME DESCRIPTION */
2357 /* */
2358 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2359 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2360 /* resulting in version 6.1 */
2361 /* */
2362 /**************************************************************************/
_nx_dhcp_load_server_options(NX_DHCP_SERVER * dhcp_ptr,NX_DHCP_CLIENT * dhcp_client_ptr,UCHAR * buffer,UINT option_type,UINT * index)2363 static UINT _nx_dhcp_load_server_options(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr, UCHAR *buffer, UINT option_type, UINT *index)
2364 {
2365
2366 UINT i;
2367 UINT iface_index;
2368 UINT renew_time;
2369 UINT rebind_time;
2370 UINT lease_time;
2371
2372
2373 /* Compute default lease, renew and rebind times to offer the client. */
2374 lease_time = dhcp_client_ptr -> nx_dhcp_requested_lease_time;
2375
2376 #if (NX_DHCP_DEFAULT_LEASE_TIME >= 0xFFFFFFFF)
2377 if (lease_time == 0)
2378 #else
2379 if ((lease_time == 0) || (lease_time > NX_DHCP_DEFAULT_LEASE_TIME))
2380 #endif
2381 {
2382 lease_time = NX_DHCP_DEFAULT_LEASE_TIME;
2383 }
2384
2385 renew_time = lease_time/2;
2386 rebind_time = 7 * (lease_time/8);
2387
2388 /* Set a local pointer for convenience. */
2389 iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index;
2390
2391 /* Determine what set of options to apply based on caller input. */
2392 if (option_type == NX_DHCP_OPTIONS_FOR_ALL_REPLIES)
2393 {
2394
2395 /* This is the generic set of options for ALL server replies. */
2396
2397 /* Set the DHCP message type the server is sending back to client. */
2398 _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_TYPE, NX_DHCP_SERVER_OPTION_DHCP_TYPE_SIZE,
2399 dhcp_client_ptr -> nx_dhcp_response_type_to_client, index);
2400
2401 /* Add the server identifier to all messages to the client. */
2402 _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_SERVER_ID, NX_DHCP_SERVER_OPTION_DHCP_SERVER_SIZE,
2403 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address, index);
2404
2405 return(NX_SUCCESS);
2406 }
2407 else if (option_type == NX_DHCP_OPTIONS_FOR_REPLY_TO_OFFER)
2408 {
2409
2410 /* Offer an IP lease. */
2411 _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_LEASE, NX_DHCP_SERVER_OPTION_DHCP_LEASE_SIZE, lease_time, index);
2412 /* With the computed renew time. */
2413 _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_RENEWAL, NX_DHCP_SERVER_OPTION_RENEWAL_SIZE, renew_time, index);
2414 /* And rebind time. */
2415 _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_REBIND, NX_DHCP_SERVER_OPTION_REBIND_SIZE, rebind_time, index);
2416 }
2417 else if (option_type == NX_DHCP_OPTIONS_FOR_REPLY_TO_REQUEST)
2418 {
2419
2420 /* Confirm the assigned IP lease, renew and rebind times. */
2421 _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_LEASE, NX_DHCP_SERVER_OPTION_DHCP_LEASE_SIZE, lease_time, index);
2422 _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_RENEWAL, NX_DHCP_SERVER_OPTION_RENEWAL_SIZE, renew_time, index);
2423 _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_REBIND, NX_DHCP_SERVER_OPTION_REBIND_SIZE, rebind_time, index);
2424 }
2425 else if (option_type == NX_DHCP_OPTIONS_FOR_REPLY_TO_INFORM)
2426 {
2427
2428 /* The NetX DHCP Server reply to Inform messages includes the standard server option
2429 list which is automatically included. */
2430 }
2431 else if (option_type == NX_DHCP_OPTIONS_FOR_GENERIC_ACK)
2432 {
2433
2434 /* Add the standard DHCP server information (e.g. subnet, router IP etc) which are
2435 appended to the required server options. */
2436 for (i= NX_DHCP_REQUIRED_SERVER_OPTION_SIZE; i < dhcp_ptr -> nx_dhcp_server_option_count; i++)
2437 {
2438
2439 /* Append this DHCP option to the client message. */
2440 _nx_dhcp_add_requested_option(dhcp_ptr, dhcp_client_ptr -> nx_dhcp_client_iface_index,
2441 buffer, dhcp_ptr -> nx_dhcp_server_options[i], index);
2442 }
2443 }
2444 else if (option_type == NX_DHCP_OPTIONS_REQUESTED_BY_CLIENT)
2445 {
2446
2447 /* The NetX DHSP Server does not (yet) support this feature in the current release. */
2448
2449 /* Clear the current DHCP Client's requested option list. */
2450 for (i = 0; i < dhcp_client_ptr -> nx_dhcp_client_option_count; i++)
2451 {
2452
2453 dhcp_client_ptr -> nx_dhcp_user_options[i] = 0;
2454 }
2455
2456 dhcp_client_ptr -> nx_dhcp_client_option_count = 0;
2457 }
2458
2459 return(NX_SUCCESS);
2460 }
2461
2462
2463 /**************************************************************************/
2464 /* */
2465 /* FUNCTION RELEASE */
2466 /* */
2467 /* _nx_dhcp_set_default_server_options PORTABLE C */
2468 /* 6.1 */
2469 /* AUTHOR */
2470 /* */
2471 /* Yuxin Zhou, Microsoft Corporation */
2472 /* */
2473 /* DESCRIPTION */
2474 /* */
2475 /* This function parses a set of options from the supplied buffer into */
2476 /* the server's list of options to supply data to the DHCP Client. If the*/
2477 /* server is configured to use default option data, it will use this list*/
2478 /* of options to compose the response to the Client. */
2479 /* */
2480 /* INPUT */
2481 /* */
2482 /* dhcp_ptr Pointer to DHCP Server */
2483 /* buffer Pointer to option list */
2484 /* size Size of option list buffer */
2485 /* */
2486 /* OUTPUT */
2487 /* */
2488 /* NX_SUCCESS Successful completion status */
2489 /* status Actual error status */
2490 /* */
2491 /* CALLS */
2492 /* */
2493 /* None */
2494 /* */
2495 /* CALLED BY */
2496 /* */
2497 /* _nx_dhcp_server_create Create the DHCP Server instance*/
2498 /* */
2499 /* RELEASE HISTORY */
2500 /* */
2501 /* DATE NAME DESCRIPTION */
2502 /* */
2503 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2504 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2505 /* resulting in version 6.1 */
2506 /* */
2507 /**************************************************************************/
_nx_dhcp_set_server_options(NX_DHCP_SERVER * dhcp_ptr,CHAR * buffer,UINT buffer_size)2508 static UINT _nx_dhcp_set_server_options(NX_DHCP_SERVER *dhcp_ptr, CHAR *buffer, UINT buffer_size)
2509 {
2510
2511 UINT j;
2512 UINT digit;
2513 UINT status;
2514 CHAR *work_ptr;
2515
2516
2517 j = 0;
2518 /* Search through the text for all options to load. */
2519 while(buffer_size && (j < NX_DHCP_SERVER_OPTION_LIST_SIZE))
2520 {
2521
2522 /* Check if we're off the end of the buffer. */
2523 if (buffer == 0x0)
2524 {
2525 break;
2526 }
2527
2528 work_ptr = buffer;
2529
2530 /* This should advance the buffer past the digit.*/
2531 status = _nx_dhcp_parse_next_option(&buffer, &digit, buffer_size);
2532 if (status)
2533 {
2534
2535 #ifdef EL_PRINTF_ENABLE
2536 EL_PRINTF("DHCPserv: Unable to set server DHCP option data list. Status 0x%x\n", status);
2537 #endif
2538
2539 return(status);
2540 }
2541
2542 buffer_size -= (UINT)(buffer - work_ptr);
2543
2544 /* Load the parsed option into the server 'option list.' */
2545 dhcp_ptr -> nx_dhcp_server_options[j] = digit;
2546 j++;
2547 }
2548
2549 /* Update the number of server options in the list. */
2550 dhcp_ptr -> nx_dhcp_server_option_count = j;
2551
2552 return(NX_SUCCESS);
2553 }
2554
2555
2556 /**************************************************************************/
2557 /* */
2558 /* FUNCTION RELEASE */
2559 /* */
2560 /* _nx_dhcp_parse_next_option PORTABLE C */
2561 /* 6.1.3 */
2562 /* AUTHOR */
2563 /* */
2564 /* Yuxin Zhou, Microsoft Corporation */
2565 /* */
2566 /* DESCRIPTION */
2567 /* */
2568 /* This function parses space or comma separated numeric data from the */
2569 /* supplied buffer, for example, the server option list. */
2570 /* */
2571 /* INPUT */
2572 /* */
2573 /* option_list Pointer to buffer to parse */
2574 /* option Data parsed from buffer */
2575 /* length Size of option list buffer */
2576 /* */
2577 /* OUTPUT */
2578 /* */
2579 /* NX_SUCCESS Successful completion status */
2580 /* NX_DHCP_INTERNAL_OPTION_PARSE_ERROR Parsing error status */
2581 /* */
2582 /* CALLS */
2583 /* */
2584 /* _nx_utility_string_to_uint Convert ascii number to integer*/
2585 /* */
2586 /* CALLED BY */
2587 /* */
2588 /* _nx_dhcp_set_default_server_options Creates the server option list */
2589 /* */
2590 /* RELEASE HISTORY */
2591 /* */
2592 /* DATE NAME DESCRIPTION */
2593 /* */
2594 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2595 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2596 /* resulting in version 6.1 */
2597 /* 12-31-2020 Yuxin Zhou Modified comment(s), fixed */
2598 /* obsolescent functions, */
2599 /* resulting in version 6.1.3 */
2600 /* */
2601 /**************************************************************************/
_nx_dhcp_parse_next_option(CHAR ** option_list,UINT * option,UINT length)2602 static UINT _nx_dhcp_parse_next_option(CHAR **option_list, UINT *option, UINT length)
2603 {
2604
2605 CHAR c;
2606 UINT j;
2607 UINT buffer_index;
2608 CHAR num_string[3];
2609 CHAR *buffer;
2610
2611
2612 /* Check for invalid input. */
2613 if ((option_list == 0x0) || (option == 0) || (length == 0))
2614 {
2615 return(NX_DHCP_INTERNAL_OPTION_PARSE_ERROR);
2616 }
2617
2618 buffer = *option_list;
2619 memset(&num_string[0], 0, 3);
2620
2621 /* Initialize parsed option to undefined option (sorry, zero is taken by the PAD option
2622 which I personally think was a bad programming decision). */
2623 *option = 999;
2624 j = 0;
2625 buffer_index = 0;
2626
2627 /* Get the first character in the buffer. */
2628 c = *buffer++;
2629
2630 /* Get the first digit (non separator character)*/
2631 while ((c == ' ') || (c == ','))
2632 {
2633
2634 c = *buffer++;
2635 j++;
2636 }
2637
2638 /* Now parse the next characters until the end of the buffer or next separator character. */
2639 while ((j < length) && (buffer_index < 3))
2640 {
2641
2642 /* Check for separator marking the end of the option string. */
2643 if ((c == ' ') || (c == ',') || (c == 0x0))
2644 break;
2645
2646 /* Check for an invalid digit or out of range option. */
2647 if (c < 0x30 || c > 0x39 || buffer_index > 2)
2648 {
2649 return(NX_DHCP_BAD_OPTION_LIST_ERROR);
2650 }
2651
2652 num_string[buffer_index] = c;
2653 j++;
2654
2655 /* Append the character ('digit') into a number buffer. */
2656 c = *buffer++;
2657 buffer_index++;
2658 }
2659
2660 *option_list += j;
2661
2662 /* Convert the number string to an actual unsigned integer. */
2663 return(_nx_utility_string_to_uint(num_string, buffer_index, option));
2664 }
2665
2666
2667 /**************************************************************************/
2668 /* */
2669 /* FUNCTION RELEASE */
2670 /* */
2671 /* _nx_dhcp_server_packet_process PORTABLE C */
2672 /* 6.1 */
2673 /* AUTHOR */
2674 /* */
2675 /* Yuxin Zhou, Microsoft Corporation */
2676 /* */
2677 /* DESCRIPTION */
2678 /* */
2679 /* This function processes a Client DHCP message and extracts */
2680 /* information from a client DHCP message to create or update the */
2681 /* client record. It handles the DHCP message based on type, sets */
2682 /* a timer on the client record if a response is expected from the */
2683 /* client, and waits for another DHCP packet. */
2684 /* */
2685 /* INPUT */
2686 /* */
2687 /* dhcp_ptr Pointer to DHCP Server */
2688 /* */
2689 /* OUTPUT */
2690 /* */
2691 /* NX_SUCCESS Message handled successfully */
2692 /* NO_PACKET No packet received */
2693 /* NX_DHCP_SERVER_BAD_INTERFACE_INDEX Packet interface not recognized*/
2694 /* status Actual completion outcome */
2695 /* */
2696 /* CALLS */
2697 /* */
2698 /* nx_packet_release Release DHCP packet */
2699 /* nx_udp_socket_receive Receive DHCP packet */
2700 /* _nx_dhcp_server_extract_information Extract DHCP packet info */
2701 /* _nx_dhcp_validate_client_message Process the Client message */
2702 /* _nx_dhcp_server_assign_ip_address Assign IP address to Client */
2703 /* _nx_dhcp_respond_to_client_message Create and send response back */
2704 /* _nx_dhcp_clear_client_session Clears client session data */
2705 /* */
2706 /* CALLED BY */
2707 /* */
2708 /* _nx_dhcp_server_thread_entry DHCP Server thread task */
2709 /* */
2710 /* RELEASE HISTORY */
2711 /* */
2712 /* DATE NAME DESCRIPTION */
2713 /* */
2714 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2715 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2716 /* resulting in version 6.1 */
2717 /* */
2718 /**************************************************************************/
_nx_dhcp_server_packet_process(NX_DHCP_SERVER * dhcp_ptr,NX_PACKET * packet_ptr)2719 static UINT _nx_dhcp_server_packet_process(NX_DHCP_SERVER *dhcp_ptr, NX_PACKET *packet_ptr)
2720 {
2721
2722 UINT status;
2723 UINT iface_index;
2724 NX_DHCP_CLIENT *dhcp_client_ptr = NX_NULL;
2725 NX_PACKET *new_packet_ptr;
2726 ULONG bytes_copied = 0;
2727 ULONG offset;
2728
2729 #ifdef EL_PRINTF_ENABLE
2730 EL_PRINTF("\n");
2731 EL_PRINTF("DHCPserv: Waiting to receive next packet\n");
2732 #endif
2733
2734 /* Check for minimum sized DHCP packet (e.g. just the DHCP header and 0 bytes of option data). */
2735 if (packet_ptr -> nx_packet_length < NX_DHCP_HEADER_SIZE)
2736 {
2737 #ifdef EL_PRINTF_ENABLE
2738 EL_PRINTF("DHCPserv: Client DHCP packet is malformed or empty. Invalid DHCP packet.\n");
2739 #endif
2740
2741 /* No; Release the original packet. */
2742 nx_packet_release(packet_ptr);
2743
2744 /* Return successful completion status. */
2745 return(NX_DHCP_MALFORMED_DHCP_PACKET);
2746 }
2747
2748 /* Get the interface index. */
2749 nx_udp_packet_info_extract(packet_ptr, NX_NULL, NX_NULL, NX_NULL, &iface_index);
2750
2751 /* Does the DHCP server have a table for this packet interface? */
2752 if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
2753 {
2754
2755 #ifdef EL_PRINTF_ENABLE
2756 EL_PRINTF("DHCPserv: No interface found for DHCP packet\n");
2757 #endif
2758
2759 /* Release the original packet. */
2760 nx_packet_release(packet_ptr);
2761
2762 /* No, return the error status. */
2763 return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX);
2764 }
2765
2766 /* We will copy the received packet (datagram) over to a packet from the DHCP Server pool and release
2767 the packet from the receive packet pool as soon as possible. */
2768 status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &new_packet_ptr, NX_IPv4_UDP_PACKET, NX_DHCP_PACKET_ALLOCATE_TIMEOUT);
2769
2770 /* Check status. */
2771 if (status != NX_SUCCESS)
2772 {
2773
2774 /* Release the original packet. */
2775 nx_packet_release(packet_ptr);
2776
2777 /* Error allocating packet, return error status. */
2778 return(status);
2779 }
2780
2781 /* Verify the incoming packet does not exceed our DHCP Server packet payload. */
2782 if ((ULONG)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < (packet_ptr -> nx_packet_length))
2783 {
2784
2785 /* Release the original packet. */
2786 nx_packet_release(packet_ptr);
2787
2788 /* Release the newly allocated packet and return an error. */
2789 nx_packet_release(new_packet_ptr);
2790
2791 return(NX_DHCP_INADEQUATE_PACKET_POOL_PAYLOAD);
2792 }
2793
2794 /* Update the prepend pointer to make sure that the IP header and UDP header also are copied into new packet. */
2795 packet_ptr -> nx_packet_prepend_ptr -= 28;
2796 packet_ptr -> nx_packet_length += 28;
2797
2798 /* Initialize the offset to the beginning of the packet buffer. */
2799 offset = 0;
2800 status = nx_packet_data_extract_offset(packet_ptr, offset, (VOID *)new_packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length, &bytes_copied);
2801
2802 /* Check status. */
2803 if ((status != NX_SUCCESS) || (bytes_copied != packet_ptr -> nx_packet_length))
2804 {
2805
2806 /* Release the original packet. */
2807 nx_packet_release(packet_ptr);
2808
2809 /* Release the allocated packet we'll never send. */
2810 nx_packet_release(new_packet_ptr);
2811
2812 /* Error extracting packet buffer, return error status. */
2813 return(status);
2814 }
2815
2816 /* Update the new packet with the bytes copied, and removed.
2817 For chained packets, this will reflect the total 'datagram' length. */
2818 new_packet_ptr -> nx_packet_prepend_ptr += 28;
2819 new_packet_ptr -> nx_packet_length = bytes_copied - 28;
2820 new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_prepend_ptr + new_packet_ptr -> nx_packet_length;
2821
2822 /* Now we can release the original packet. */
2823 nx_packet_release(packet_ptr);
2824
2825 /* Extract the DHCP specific information from the packet. This will create new record or update existing
2826 client record in the server database. */
2827 status = _nx_dhcp_server_extract_information(dhcp_ptr, &dhcp_client_ptr, new_packet_ptr, iface_index);
2828
2829 #ifdef PACKET_DUMP
2830 {
2831
2832 ULONG *work_ptr;
2833 ULONG uword;
2834 UINT i = 0;
2835 UINT index = 0;
2836 UINT length;
2837
2838 #ifdef EL_PRINTF_ENABLE
2839 EL_PRINTF("DHCPserv: received client packet dump:\n");
2840 #endif
2841
2842 /* Get a pointer to the IP header and adjust the packet length for IP and UDP header size. */
2843 work_ptr = (ULONG *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV4_HEADER));
2844 length = ((packet_ptr -> nx_packet_length + sizeof(ULONG) - 1)/sizeof(ULONG)) + sizeof(NX_UDP_HEADER) + sizeof(NX_IPV4_HEADER);
2845
2846 while(i < length)
2847 {
2848 uword = *work_ptr;
2849
2850 if (index == 10)
2851 {
2852
2853 #ifdef EL_PRINTF_ENABLE
2854 EL_PRINTF("\n");
2855 #endif
2856 index = 0;
2857 }
2858 #ifdef EL_PRINTF_ENABLE
2859 EL_PRINTF(" %08x", uword);
2860 #endif
2861 work_ptr++;
2862 index++;
2863 i++;
2864 }
2865 #ifdef EL_PRINTF_ENABLE
2866 EL_PRINTF("\n\n");
2867 #endif
2868 }
2869 #endif /* #ifdef PACKET_DUMP */
2870
2871 /* We are done with this packet now regardless of the success of the above operations. */
2872 nx_packet_release(new_packet_ptr);
2873
2874 /* Check if we have an invalid client record. */
2875 if ((status != NX_SUCCESS) && dhcp_client_ptr)
2876 {
2877
2878 #ifdef EL_PRINTF_ENABLE
2879 EL_PRINTF("DHCPserv: Error extracting DHCP packet (invalid): 0x%x\n", status);
2880 #endif
2881
2882 /* Client record was created but there was a problem with the packet
2883 or client message. Since we're not sure what got written to the Client record,
2884 remove packet data out completely. */
2885 _nx_dhcp_clear_client_record(dhcp_ptr, dhcp_client_ptr);
2886 }
2887
2888 /* Check for general errors or failure to produce a client record. */
2889 if ((status != NX_SUCCESS) || !dhcp_client_ptr)
2890 {
2891
2892 #ifdef EL_PRINTF_ENABLE
2893 EL_PRINTF("DHCPserv: Internal error extracting DHCP packet: 0x%x\n", status);
2894 #endif
2895
2896 /* Return the error from extracting packet data. */
2897 return(status);
2898 }
2899
2900 /* Clear any previous response type in the client record. */
2901 dhcp_client_ptr -> nx_dhcp_response_type_to_client = 0;
2902
2903 /* Validate the client message including how the server should respond to it. */
2904 status = _nx_dhcp_validate_client_message(dhcp_ptr, dhcp_client_ptr);
2905
2906 /* Check for errors. */
2907 if (status != NX_SUCCESS)
2908 {
2909
2910 #ifdef EL_PRINTF_ENABLE
2911 EL_PRINTF("DHCPserv: DHCP packet failed validation: 0x%x\n", status);
2912 #endif
2913
2914 /* Return all other errors as completion status. Do not send a message to the client. */
2915 return(status);
2916 }
2917
2918 /* Assign/confirm the assigned IP address of the Client if the server is not returning
2919 a NACK, responding to an INFORM message, or not responding at all. */
2920 if ((dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPNACK) &&
2921 (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPSILENT) &&
2922 (dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPINFORM))
2923 {
2924
2925 #ifdef EL_PRINTF_ENABLE
2926 EL_PRINTF("DHCPserv: assigning IP address to DHCP client...\n");
2927 #endif
2928
2929 /* Assign/confirm an IP address to the client. If the client is renewing or rebinding
2930 this will verify they sent the correct IP address and reset the lease time. */
2931 status = _nx_dhcp_server_assign_ip_address(dhcp_ptr, dhcp_client_ptr);
2932
2933 /* Has the server run out of available addresses? Handle this 'error'
2934 condition separately. */
2935 if (status == NX_DHCP_NO_AVAILABLE_IP_ADDRESSES)
2936 {
2937
2938 #ifdef EL_PRINTF_ENABLE
2939 EL_PRINTF("DHCPserv: Unable to assign IP address; none available\n");
2940 #endif
2941
2942 /* Actually as yet, there is no callback to the host application
2943 for handling this situation.
2944
2945 The server should still send a NACK to the Client that it cannot
2946 provide what it requests. */
2947 }
2948 /* Check for errors other than running out of available IP addresses. */
2949 else if (status != NX_SUCCESS)
2950 {
2951
2952 #ifdef EL_PRINTF_ENABLE
2953 EL_PRINTF("DHCPserv: Unable to assign IP address. Status: 0x%x\n", status);
2954 #endif
2955
2956 /* Return all other errors as completion status. Do not send a message to the client. */
2957 return(status);
2958 }
2959 }
2960
2961 #ifdef EL_PRINTF_ENABLE
2962 if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPOFFER)
2963 EL_PRINTF("DHCPserv: response to client: OFFER\n");
2964 else if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPACK)
2965 EL_PRINTF("DHCPserv: response to client: ACK\n");
2966 else if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPNACK)
2967 EL_PRINTF("DHCPserv: response to client: NACK\n");
2968 else if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPSILENT)
2969 EL_PRINTF("DHCPserv: response to client: SILENT (no response)\n");
2970 #endif
2971
2972
2973 /* Is there a response to send to the Client? */
2974 if (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPSILENT)
2975 {
2976
2977 /* Yes; use the session data in the client record to compose the server reply. */
2978 status = _nx_dhcp_respond_to_client_message(dhcp_ptr, dhcp_client_ptr);
2979
2980 /* Check for error. */
2981 if (status != NX_SUCCESS)
2982 {
2983
2984 #ifdef EL_PRINTF_ENABLE
2985 EL_PRINTF("DHCPserv: Error sending response to DHCP client. Status: 0x%x\n", status);
2986 #endif
2987
2988 /* Return error completion status. Error sending a message to client. */
2989 return(status);
2990 }
2991
2992 /* Update the client state if an ACK was sent successfully. */
2993 if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPACK)
2994 {
2995
2996 /* Was the client was in a requesting, renewing or rebinding state? */
2997 if ((dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_RENEWING) ||
2998 (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_REBINDING) ||
2999 (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_REQUESTING))
3000 {
3001
3002 /* Yes, the client should now be bound to an IP address. */
3003 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_BOUND;
3004 }
3005 }
3006 }
3007
3008 /*
3009 If the Client is BOUND, the session is over. Clear the session including
3010 the sesison timeout.
3011
3012 If the Client is still in the BOOT or INIT state something was wrong with their
3013 message or else the server had a problem. Clear the record and they
3014 can start a new session with a retransmission of their request.
3015 */
3016
3017 /* Do we need to clear the session data depending? */
3018 if (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_BOOT ||
3019 dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_INIT ||
3020 dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_BOUND)
3021 {
3022
3023 #ifdef EL_PRINTF_ENABLE
3024 EL_PRINTF("DHCPserv: client session completed. Clear session data.\n");
3025 #endif
3026
3027 /* Yes, clear all data from the session. Client assigned IP address
3028 and hardware address are not cleared.*/
3029 _nx_dhcp_clear_client_session(dhcp_ptr,dhcp_client_ptr);
3030 }
3031 else
3032 {
3033
3034 #ifdef EL_PRINTF_ENABLE
3035 EL_PRINTF("DHCPserv: Waiting for DHCP client response...\n");
3036 #endif
3037
3038 /* No; assume the Client is Renewing, rebinding, or selecting,
3039 to set the session timeout to await the next Client response;
3040 (not finished with this DHCP session yet). */
3041
3042 /* Assume we have received at least one message from the Client, so
3043 reset the timer on the client session timeout. */
3044 dhcp_client_ptr -> nx_dhcp_session_timeout = NX_DHCP_CLIENT_SESSION_TIMEOUT;
3045 }
3046
3047
3048 /* Output Server session data if enabled. */
3049 #ifdef TESTOUTPUT
3050 add_client++;
3051
3052 /* Only print out the session table depending on trace interval. */
3053 if ((TRACE_NTH_CLIENT_PACKET > 0) && (add_client % TRACE_NTH_CLIENT_PACKET == 0))
3054 {
3055
3056 UINT i;
3057
3058 #ifdef EL_PRINTF_ENABLE
3059 EL_PRINTF("\nClient\t\tAssigned\tLease\t\tSession\tState\n");
3060 #endif
3061 for (i = 0; i < dhcp_ptr -> nx_dhcp_number_clients; i++)
3062 {
3063 NX_DHCP_CLIENT *client_ptr;
3064
3065 client_ptr = &(dhcp_ptr -> client_records[i]);
3066
3067 #ifdef EL_PRINTF_ENABLE
3068 EL_PRINTF("0x%x 0x%x\t0x%08x\t0x%08x\t%d\t%d\n",
3069 client_ptr -> nx_dhcp_client_mac_msw,
3070 client_ptr -> nx_dhcp_client_mac_lsw,
3071 client_ptr -> nx_dhcp_assigned_ip_address,
3072 client_ptr -> nx_dhcp_requested_lease_time,
3073 client_ptr -> nx_dhcp_session_timeout,
3074 client_ptr -> nx_dhcp_client_state);
3075 #endif
3076 }
3077
3078 #ifdef EL_PRINTF_ENABLE
3079 EL_PRINTF("\nHost\tIP address\tAssigned? Lease\n");
3080 EL_PRINTF("Interface 0\n");
3081 for (i = 0; i < dhcp_ptr -> nx_dhcp_interface_table[0].nx_dhcp_address_list_size; i++)
3082 {
3083 NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr;
3084
3085 interface_address_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[0].nx_dhcp_ip_address_list[i]);
3086 EL_PRINTF("0x%x 0x%x\t0x%x\t%d\t 0x%x\n",
3087 interface_address_ptr -> owner_mac_msw,
3088 interface_address_ptr -> owner_mac_lsw,
3089 interface_address_ptr -> nx_assignable_ip_address,
3090 interface_address_ptr -> assigned,
3091 interface_address_ptr -> lease_time);
3092 }
3093
3094 EL_PRINTF("\nInterface 1\n");
3095 for (i = 0; i < dhcp_ptr -> nx_dhcp_interface_table[1].nx_dhcp_address_list_size; i++)
3096 {
3097 NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr;
3098
3099 interface_address_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[1].nx_dhcp_ip_address_list[i]);
3100 EL_PRINTF("0x%x 0x%x\t0x%x\t%d\t 0x%x\n",
3101 interface_address_ptr -> owner_mac_msw,
3102 interface_address_ptr -> owner_mac_lsw,
3103 interface_address_ptr -> nx_assignable_ip_address,
3104 interface_address_ptr -> assigned,
3105 interface_address_ptr -> lease_time);
3106 }
3107 #endif
3108 }
3109 #endif
3110
3111 /* Return actual outcome status. */
3112 return(status);
3113 }
3114
3115
3116 /**************************************************************************/
3117 /* */
3118 /* FUNCTION RELEASE */
3119 /* */
3120 /* _nx_dhcp_find_client_record_by_ip_address PORTABLE C */
3121 /* 6.1 */
3122 /* AUTHOR */
3123 /* */
3124 /* Yuxin Zhou, Microsoft Corporation */
3125 /* */
3126 /* DESCRIPTION */
3127 /* */
3128 /* This function looks up a client record using the client's last known*/
3129 /* assigned IP address. */
3130 /* */
3131 /* INPUT */
3132 /* */
3133 /* dhcp_ptr Pointer to DHCP server */
3134 /* dhcp_client_ptr Pointer to DHCP client */
3135 /* iface_index Client network interface index*/
3136 /* assigned_ip_address Client's assigned IP address */
3137 /* */
3138 /* OUTPUT */
3139 /* */
3140 /* NX_SUCCESS Successful completion */
3141 /* NX_DHCP_CLIENT_RECORD_NOT_FOUND Client record not found in */
3142 /* Server database */
3143 /* */
3144 /* CALLS */
3145 /* */
3146 /* _nx_dhcp_clear_client_record Remove Client record from */
3147 /* Server database */
3148 /* */
3149 /* CALLED BY */
3150 /* */
3151 /* _nx_dhcp_slow_periodic_timer_entry Update IP lease time outs */
3152 /* */
3153 /* RELEASE HISTORY */
3154 /* */
3155 /* DATE NAME DESCRIPTION */
3156 /* */
3157 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3158 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3159 /* resulting in version 6.1 */
3160 /* */
3161 /**************************************************************************/
_nx_dhcp_find_client_record_by_ip_address(NX_DHCP_SERVER * dhcp_ptr,NX_DHCP_CLIENT ** dhcp_client_ptr,UINT iface_index,ULONG assigned_ip_address)3162 UINT _nx_dhcp_find_client_record_by_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr,
3163 UINT iface_index, ULONG assigned_ip_address)
3164 {
3165
3166 UINT i;
3167 NX_DHCP_CLIENT *client_record_ptr;
3168
3169
3170 /* Initialize the search results to unsuccessful. */
3171 *dhcp_client_ptr = NX_NULL;
3172
3173 i = 0;
3174
3175 /* Records are not necessarily added and deleted sequentially,
3176 so search the whole table until a match is found. */
3177 while (i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE)
3178 {
3179 /* Set local pointer for convenience. */
3180 client_record_ptr = &dhcp_ptr -> client_records[i];
3181
3182 /* Check the mac address for a match. */
3183 if (client_record_ptr -> nx_dhcp_assigned_ip_address == assigned_ip_address)
3184 {
3185
3186 /* Verify the client packet interface matches the interface on record. */
3187 if (client_record_ptr -> nx_dhcp_client_iface_index == iface_index)
3188 {
3189 /* Return the client record location. */
3190 *dhcp_client_ptr = client_record_ptr;
3191
3192 return(NX_SUCCESS);
3193 }
3194 else
3195 {
3196
3197 /* It appears the client has changed its subnet location but not hardware type e.g.
3198 same mac address/hardware type but not interface. Clear the old record. */
3199
3200 /* This will remove the client record both in the
3201 server's client table and in the IP address database. */
3202 _nx_dhcp_clear_client_record(dhcp_ptr, client_record_ptr);
3203
3204 /* Search through the rest of the server records for
3205 another instance of this client. Either way, if not found
3206 with the expected interface a null pointer is returned,
3207 or new record created depending on the caller. */
3208 }
3209 }
3210 i++;
3211 }
3212
3213 return(NX_DHCP_CLIENT_RECORD_NOT_FOUND);
3214 }
3215
3216
3217 /**************************************************************************/
3218 /* */
3219 /* FUNCTION RELEASE */
3220 /* */
3221 /* _nx_dhcp_find_client_record_by_chaddr PORTABLE C */
3222 /* 6.1 */
3223 /* AUTHOR */
3224 /* */
3225 /* Yuxin Zhou, Microsoft Corporation */
3226 /* */
3227 /* DESCRIPTION */
3228 /* */
3229 /* This function looks up a client record by the client hardware mac */
3230 /* address. */
3231 /* */
3232 /* INPUT */
3233 /* */
3234 /* dhcp_ptr Pointer to DHCP Server */
3235 /* iface_index Client interface index */
3236 /* client_mac_msw MSB of client hardware address*/
3237 /* client_mac_lsw LSB of client hardware address*/
3238 /* dhcp_client_ptr Pointer to client record entry*/
3239 /* add_on Option to add if not found */
3240 /* */
3241 /* OUTPUT */
3242 /* */
3243 /* NX_SUCCESS Message handled successfully */
3244 /* NX_DHCP_CLIENT_TABLE_FULL No more room in Client table */
3245 /* */
3246 /* CALLS */
3247 /* */
3248 /* _nx_dhcp_clear_client_record Removes client record from */
3249 /* server table */
3250 /* */
3251 /* CALLED BY */
3252 /* */
3253 /* _nx_dhcp_server_extract_information Extract DHCP info from Client */
3254 /* message */
3255 /* */
3256 /* RELEASE HISTORY */
3257 /* */
3258 /* DATE NAME DESCRIPTION */
3259 /* */
3260 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3261 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3262 /* resulting in version 6.1 */
3263 /* */
3264 /**************************************************************************/
_nx_dhcp_find_client_record_by_chaddr(NX_DHCP_SERVER * dhcp_ptr,UINT iface_index,ULONG client_mac_msw,ULONG client_mac_lsw,NX_DHCP_CLIENT ** dhcp_client_ptr,UINT add_on)3265 static UINT _nx_dhcp_find_client_record_by_chaddr(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG client_mac_msw,
3266 ULONG client_mac_lsw, NX_DHCP_CLIENT **dhcp_client_ptr, UINT add_on)
3267 {
3268
3269 UINT i;
3270 UINT available_index;
3271 NX_DHCP_CLIENT *client_record_ptr;
3272
3273
3274 /* Initialize the search results to unsuccessful. */
3275 *dhcp_client_ptr = NX_NULL;
3276
3277 /* Initialize an available slot in the table as outside the boundary (e.g. no slots available). */
3278 available_index = NX_DHCP_CLIENT_RECORD_TABLE_SIZE;
3279
3280 /* Records are not necessarily added and deleted sequentially,
3281 so search the whole table until a match is found. */
3282 i = 0;
3283 while (i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE)
3284 {
3285
3286 /* Set local pointer for convenience. */
3287 client_record_ptr = &dhcp_ptr -> client_records[i];
3288
3289 /* Skip empty records. Assume a client with no mac address is empty. */
3290 if ((client_record_ptr -> nx_dhcp_client_mac_msw == 0) && (client_record_ptr -> nx_dhcp_client_mac_lsw == 0))
3291 {
3292
3293 /* Flag the first empty record in case we need to add the current client to the table. */
3294 if (i < available_index)
3295 available_index = i;
3296
3297 i++;
3298 continue;
3299 }
3300
3301 /* Check the mac address of each record for a match. */
3302 if ((client_record_ptr -> nx_dhcp_client_mac_msw == client_mac_msw) &&
3303 (client_record_ptr -> nx_dhcp_client_mac_lsw == client_mac_lsw))
3304 {
3305
3306 /* Verify the client packet interface matches the interface on record. */
3307 if (client_record_ptr -> nx_dhcp_client_iface_index == iface_index)
3308 {
3309 /* Return the client record location. */
3310 *dhcp_client_ptr = client_record_ptr;
3311
3312 return(NX_SUCCESS);
3313 }
3314 else
3315 {
3316
3317 /* It appears the client has changed its location (subnet) but not hardware type e.g. same mac
3318 address/hware type but not interface. Remove the client record entirely and
3319 free up any assigned IP address in the server database. */
3320 _nx_dhcp_clear_client_record(dhcp_ptr, client_record_ptr);
3321
3322 /* Continue searching through the rest of the server records for
3323 another instance of this client. Either way, if not found
3324 with the expected interface a null pointer is returned,
3325 or new record created depending on the caller. */
3326 }
3327 }
3328
3329 i++;
3330 }
3331
3332 /* Not found. Create a record for this client? */
3333 if (add_on == NX_FALSE)
3334 {
3335
3336 #ifdef EL_PRINTF_ENABLE
3337 EL_PRINTF("DHCPserv: Client HW address not found. Do not add to server database\n");
3338 #endif
3339
3340 /* No, we're done then. */
3341 return(NX_SUCCESS);
3342 }
3343
3344 /* Check if there is available room in the table for a new client. */
3345 if (available_index >= NX_DHCP_CLIENT_RECORD_TABLE_SIZE)
3346 {
3347
3348 /* No, we cannot add this client so the server's table. */
3349 return(NX_DHCP_CLIENT_TABLE_FULL);
3350 }
3351
3352 /* Set local pointer to an available slot. */
3353 client_record_ptr = &dhcp_ptr -> client_records[available_index];
3354
3355 /* Add this client to the server's total number of clients. */
3356 dhcp_ptr -> nx_dhcp_number_clients++;
3357
3358 /* Add the supplied information to the new client record. */
3359 client_record_ptr -> nx_dhcp_client_mac_msw = client_mac_msw;
3360 client_record_ptr -> nx_dhcp_client_mac_lsw = client_mac_lsw;
3361 client_record_ptr -> nx_dhcp_client_iface_index = iface_index;
3362
3363 /* Initialize the client state as the init state. */
3364 client_record_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
3365
3366 /* Return the location of the newly created client record. */
3367 *dhcp_client_ptr = client_record_ptr;
3368
3369 return(NX_SUCCESS);
3370 }
3371
3372
3373 /**************************************************************************/
3374 /* */
3375 /* FUNCTION RELEASE */
3376 /* */
3377 /* _nx_dhcp_find_interface_table_ip_address PORTABLE C */
3378 /* 6.1 */
3379 /* AUTHOR */
3380 /* */
3381 /* Yuxin Zhou, Microsoft Corporation */
3382 /* */
3383 /* DESCRIPTION */
3384 /* */
3385 /* This function looks up a table entry by IP address in the specified */
3386 /* server interface table. If not found, a NULL entry pointer is */
3387 /* returned but successful search completion. */
3388 /* */
3389 /* INPUT */
3390 /* */
3391 /* dhcp_ptr Pointer to DHCP Server */
3392 /* iface_index Network interface index */
3393 /* ip_address IP address to look up */
3394 /* return_interface_address Pointer to table entry */
3395 /* */
3396 /* OUTPUT */
3397 /* */
3398 /* NX_SUCCESS Message handled successfully */
3399 /* */
3400 /* CALLS */
3401 /* */
3402 /* _nx_dhcp_clear_client_record Removes client record from */
3403 /* server table */
3404 /* */
3405 /* CALLED BY */
3406 /* */
3407 /* _nx_dhcp_server_extract_information Extract DHCP info from Client */
3408 /* message */
3409 /* */
3410 /* RELEASE HISTORY */
3411 /* */
3412 /* DATE NAME DESCRIPTION */
3413 /* */
3414 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3415 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3416 /* resulting in version 6.1 */
3417 /* */
3418 /**************************************************************************/
_nx_dhcp_find_interface_table_ip_address(NX_DHCP_SERVER * dhcp_ptr,UINT iface_index,ULONG ip_address,NX_DHCP_INTERFACE_IP_ADDRESS ** return_interface_address)3419 static UINT _nx_dhcp_find_interface_table_ip_address(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG ip_address,
3420 NX_DHCP_INTERFACE_IP_ADDRESS **return_interface_address)
3421 {
3422
3423 UINT i;
3424 NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr;
3425
3426
3427 /* Initialize search results to NULL (not found). */
3428 *return_interface_address = NX_NULL;
3429
3430 /* Set a local varible to the IP address list for this client. */
3431 dhcp_interface_table_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[iface_index]);
3432
3433 /* Yes, search for an available ip address in the IP list for this interface */
3434 for(i = 0; i < dhcp_interface_table_ptr -> nx_dhcp_address_list_size; i++)
3435 {
3436
3437 /* Is this address a match? */
3438 if (dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i].nx_assignable_ip_address == ip_address)
3439 {
3440 /* Yes, set a pointer to the location and return. */
3441 *return_interface_address = &dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i];
3442
3443 /* And we're done! */
3444 return(NX_SUCCESS);
3445 }
3446 }
3447
3448 /* Not found, so return null pointer and successful search status. */
3449 return(NX_SUCCESS);
3450 }
3451
3452
3453 /**************************************************************************/
3454 /* */
3455 /* FUNCTION RELEASE */
3456 /* */
3457 /* _nx_dhcp_update_assignable_ip_address PORTABLE C */
3458 /* 6.1 */
3459 /* AUTHOR */
3460 /* */
3461 /* Yuxin Zhou, Microsoft Corporation */
3462 /* */
3463 /* DESCRIPTION */
3464 /* */
3465 /* This function updates the IP address status in the server interface */
3466 /* table address for the current client. This will return an error */
3467 /* status if the IP address being updated is not owned by the client. */
3468 /* */
3469 /* Note: No changes are made to the associated client record. */
3470 /* */
3471 /* INPUT */
3472 /* */
3473 /* dhcp_ptr Pointer to DHCP Server */
3474 /* dhcp_client_ptr Pointer to DHCP client */
3475 /* ip_address IP address to update */
3476 /* assign_status Status to assign */
3477 /* */
3478 /* OUTPUT */
3479 /* */
3480 /* NX_SUCCESS Entry updated successfully */
3481 /* NX_DHCP_IP_ADDRESS_NOT_FOUND IP address not found */
3482 /* NX_DHCP_IP_ADDRESS_ASSIGNED_TO_OTHER IP address not assigned to */
3483 /* current client */
3484 /* NX_DHCP_INVALID_UPDATE_ADDRESS_CMD Unknown status input */
3485 /* */
3486 /* CALLS */
3487 /* */
3488 /* _nx_dhcp_find_interface_table_ip_address */
3489 /* Find IP address in server */
3490 /* interface table */
3491 /* _nx_dhcp_find_ip_address_owner Verify Client is address owner */
3492 /* _nx_dhcp_clear_ip_address_owner Clear IP address owner */
3493 /* _nx_dhcp_record_ip_address_owner Sets Client as IP address owner */
3494 /* */
3495 /* CALLED BY */
3496 /* */
3497 /* _nx_dhcp_validate_client_message Process DHCP Client message*/
3498 /* _nx_dhcp_fast_periodic_timer_entry Timer on client sessions */
3499 /* _nx_dhcp_slow_periodic_timer_entry Timer on IP address leases */
3500 /* message */
3501 /* */
3502 /* RELEASE HISTORY */
3503 /* */
3504 /* DATE NAME DESCRIPTION */
3505 /* */
3506 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3507 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3508 /* resulting in version 6.1 */
3509 /* */
3510 /**************************************************************************/
_nx_dhcp_update_assignable_ip_address(NX_DHCP_SERVER * dhcp_ptr,NX_DHCP_CLIENT * dhcp_client_ptr,ULONG ip_address,UINT assign_status)3511 static UINT _nx_dhcp_update_assignable_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr,
3512 ULONG ip_address, UINT assign_status)
3513 {
3514
3515 UINT iface_index;
3516 UINT assigned_to_client;
3517 UINT lease_time;
3518 NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr;
3519
3520
3521 /* Create a local variable for convenience. */
3522 iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index;
3523
3524 /* Look up the IP address in the server interface IP address table. */
3525 _nx_dhcp_find_interface_table_ip_address(dhcp_ptr, iface_index, ip_address, &interface_address_ptr);
3526
3527 /* Was it found? */
3528 if (interface_address_ptr == 0x0)
3529 {
3530
3531 /* No, return an error status address not found. */
3532 return(NX_DHCP_IP_ADDRESS_NOT_FOUND);
3533 }
3534
3535 /* Is the Client releasing IP address? */
3536 if (assign_status == NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE)
3537 {
3538
3539 /* Check if owner of this IP address matches with this client's record. */
3540 _nx_dhcp_find_ip_address_owner(interface_address_ptr, dhcp_client_ptr, &assigned_to_client);
3541
3542 /* Is the IP address owned (leased) to this client? */
3543 if (assigned_to_client == NX_FALSE)
3544 {
3545
3546 /* No, this IP address is assigned to another host. We cannot change
3547 the IP address status. */
3548 return(NX_DHCP_IP_ADDRESS_ASSIGNED_TO_OTHER);
3549 }
3550
3551 /* Yes, clear the owner information. */
3552 _nx_dhcp_clear_ip_address_owner(interface_address_ptr);
3553 }
3554
3555 /* Was the IP address assigned externally from the DHCP process? */
3556 else if (assign_status == NX_DHCP_ADDRESS_STATUS_ASSIGNED_EXT)
3557 {
3558
3559 /* Check the lease time. */
3560 if (interface_address_ptr -> lease_time)
3561 {
3562 /* If this already has a lease time (because we assigned it most likely) don't change it. */
3563 lease_time = interface_address_ptr -> lease_time;
3564 }
3565 else
3566 {
3567 /* Otherwise, make this lease time infinity e.g. the time out will not expire on it.*/
3568 lease_time = NX_WAIT_FOREVER;
3569 }
3570
3571 /* Set the current client as the owner. */
3572 _nx_dhcp_record_ip_address_owner(interface_address_ptr, dhcp_client_ptr, lease_time);
3573 }
3574
3575 /* Is the client informing us the IP address is already in use (e.g. it has
3576 sent the server a DECLINE message) or accepting another DHCP server's offer? */
3577 else if (assign_status == NX_DHCP_ADDRESS_STATUS_ASSIGNED_OTHER)
3578 {
3579
3580 /* Yes; Is the client is declining the IP address? */
3581 if (dhcp_client_ptr -> nx_dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE)
3582 {
3583
3584 /* Yes, remove the Client as owner of this IP lease.
3585 Record owner information with null 'owner' ID since we don't know who the owner is. */
3586 _nx_dhcp_record_ip_address_owner(interface_address_ptr, NX_NULL, NX_WAIT_FOREVER);
3587 }
3588 else
3589 {
3590
3591 /* Record owner information. */
3592 _nx_dhcp_record_ip_address_owner(interface_address_ptr, dhcp_client_ptr, NX_WAIT_FOREVER);
3593 }
3594 }
3595 else
3596 {
3597
3598 /* Received an invalid update address command. */
3599 return(NX_DHCP_INVALID_UPDATE_ADDRESS_CMD);
3600 }
3601
3602 /* Successful completion! */
3603 return(NX_SUCCESS);
3604 }
3605
3606
3607 /**************************************************************************/
3608 /* */
3609 /* FUNCTION RELEASE */
3610 /* */
3611 /* _nx_dhcp_find_ip_address_owner PORTABLE C */
3612 /* 6.1 */
3613 /* AUTHOR */
3614 /* */
3615 /* Yuxin Zhou, Microsoft Corporation */
3616 /* */
3617 /* DESCRIPTION */
3618 /* */
3619 /* This function finds the owner of the specified IP address and checks*/
3620 /* it against the specified client record to insure the client is the */
3621 /* owner of the IP address. The result of the search is updated in the */
3622 /* assigned_to_client pointer. */
3623 /* */
3624 /* INPUT */
3625 /* */
3626 /* iface_owner Pointer to table entry */
3627 /* dhcp_client_ptr Pointer to DHCP client */
3628 /* assign_status Status to assign */
3629 /* */
3630 /* OUTPUT */
3631 /* */
3632 /* NX_SUCCESS Table searched successfully */
3633 /* */
3634 /* CALLS */
3635 /* */
3636 /* None */
3637 /* */
3638 /* CALLED BY */
3639 /* */
3640 /* _nx_dhcp_update_assignable_ip_address Update IP address status in */
3641 /* the server database */
3642 /* _nx_dhcp_server_assign_ip_address Assign an IP address to the */
3643 /* current client */
3644 /* */
3645 /* RELEASE HISTORY */
3646 /* */
3647 /* DATE NAME DESCRIPTION */
3648 /* */
3649 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3650 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3651 /* resulting in version 6.1 */
3652 /* */
3653 /**************************************************************************/
_nx_dhcp_find_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS * iface_owner,NX_DHCP_CLIENT * client_record_ptr,UINT * assigned_to_client)3654 static UINT _nx_dhcp_find_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT *assigned_to_client)
3655 {
3656
3657
3658 /* Initialize the value. */
3659 *assigned_to_client = NX_FALSE;
3660
3661 /* Compare the owner in the interface table entry with the client record mac address. */
3662 if ((iface_owner -> owner_hwtype == client_record_ptr -> nx_dhcp_client_hwtype) &&
3663 (iface_owner -> owner_mac_msw == client_record_ptr -> nx_dhcp_client_mac_msw) &&
3664 (iface_owner -> owner_mac_lsw == client_record_ptr -> nx_dhcp_client_mac_lsw))
3665 {
3666
3667 /* They match; This verifies the IP address is assigned to this client. */
3668 *assigned_to_client = NX_TRUE;
3669 }
3670
3671 return(NX_SUCCESS);
3672 }
3673
3674
3675 /**************************************************************************/
3676 /* */
3677 /* FUNCTION RELEASE */
3678 /* */
3679 /* _nx_dhcp_record_ip_address_owner PORTABLE C */
3680 /* 6.1 */
3681 /* AUTHOR */
3682 /* */
3683 /* Yuxin Zhou, Microsoft Corporation */
3684 /* */
3685 /* DESCRIPTION */
3686 /* */
3687 /* This function fills in the address owner in the interface table from*/
3688 /* the specified client record. */
3689 /* */
3690 /* INPUT */
3691 /* */
3692 /* iface_owner Pointer to table entry */
3693 /* client_record_ptr Pointer to DHCP client */
3694 /* lease_time Lease duration in secs */
3695 /* */
3696 /* OUTPUT */
3697 /* */
3698 /* NX_SUCCESS Table searched successfully */
3699 /* */
3700 /* CALLS */
3701 /* */
3702 /* None */
3703 /* */
3704 /* CALLED BY */
3705 /* */
3706 /* _nx_dhcp_update_assignable_ip_address Update IP address status in */
3707 /* the server database */
3708 /* _nx_dhcp_server_assign_ip_address Assign an IP address to the */
3709 /* current client */
3710 /* */
3711 /* RELEASE HISTORY */
3712 /* */
3713 /* DATE NAME DESCRIPTION */
3714 /* */
3715 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3716 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3717 /* resulting in version 6.1 */
3718 /* */
3719 /**************************************************************************/
_nx_dhcp_record_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS * iface_owner,NX_DHCP_CLIENT * client_record_ptr,UINT lease_time)3720 static UINT _nx_dhcp_record_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT lease_time)
3721 {
3722
3723 /* Check the client_record_ptr. */
3724 if (client_record_ptr)
3725 {
3726
3727 /* Parse the mac address and hardware type from the client record. */
3728 iface_owner -> owner_hwtype = client_record_ptr -> nx_dhcp_client_hwtype;
3729 iface_owner -> owner_mac_msw = client_record_ptr -> nx_dhcp_client_mac_msw;
3730 iface_owner -> owner_mac_lsw = client_record_ptr -> nx_dhcp_client_mac_lsw;
3731 }
3732 else
3733 {
3734
3735 /* We don't know who the owner is, set the owner information as zero. */
3736 iface_owner -> owner_hwtype = 0;
3737 iface_owner -> owner_mac_msw = 0;
3738 iface_owner -> owner_mac_lsw = 0;;
3739 }
3740
3741 /* Record the lease time. */
3742 iface_owner -> lease_time = lease_time;
3743
3744 /* Set the assigned status. */
3745 iface_owner -> assigned = NX_TRUE;
3746
3747 /* Return. */
3748 return(NX_SUCCESS);
3749 }
3750
3751
3752 /**************************************************************************/
3753 /* */
3754 /* FUNCTION RELEASE */
3755 /* */
3756 /* _nx_dhcp_clear_ip_address_owner PORTABLE C */
3757 /* 6.1 */
3758 /* AUTHOR */
3759 /* */
3760 /* Yuxin Zhou, Microsoft Corporation */
3761 /* */
3762 /* DESCRIPTION */
3763 /* */
3764 /* This function clears the address owner information. */
3765 /* */
3766 /* INPUT */
3767 /* */
3768 /* iface_owner Pointer to table entry */
3769 /* */
3770 /* OUTPUT */
3771 /* */
3772 /* NX_SUCCESS */
3773 /* */
3774 /* CALLS */
3775 /* */
3776 /* None */
3777 /* */
3778 /* CALLED BY */
3779 /* */
3780 /* _nx_dhcp_slow_periodic_timer_entry Update IP lease time outs */
3781 /* _nx_dhcp_clear_client_record Clear Client record */
3782 /* _nx_dhcp_update_assignable_ip_address Update IP address status in */
3783 /* the server database */
3784 /* _nx_dhcp_server_assign_ip_address Assign an IP address to the */
3785 /* current client */
3786 /* */
3787 /* RELEASE HISTORY */
3788 /* */
3789 /* DATE NAME DESCRIPTION */
3790 /* */
3791 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3792 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3793 /* resulting in version 6.1 */
3794 /* */
3795 /**************************************************************************/
_nx_dhcp_clear_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS * iface_owner)3796 static UINT _nx_dhcp_clear_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner)
3797 {
3798
3799 /* Clear the owner information. */
3800 iface_owner -> owner_hwtype = 0;
3801 iface_owner -> owner_mac_msw = 0;
3802 iface_owner -> owner_mac_lsw = 0;
3803
3804 /* Clear the lease time. */
3805 iface_owner -> lease_time = 0;
3806
3807 /* Clear the assigned status. */
3808 iface_owner -> assigned = NX_FALSE;
3809
3810 /* Return. */
3811 return(NX_SUCCESS);
3812 }
3813
3814
3815 /**************************************************************************/
3816 /* */
3817 /* FUNCTION RELEASE */
3818 /* */
3819 /* _nx_dhcp_validate_client_message PORTABLE C */
3820 /* 6.1 */
3821 /* AUTHOR */
3822 /* */
3823 /* Yuxin Zhou, Microsoft Corporation */
3824 /* */
3825 /* DESCRIPTION */
3826 /* */
3827 /* This function verifies the client message is a valid DHCP request, */
3828 /* determines if an IP address need to be assigned, what state the DHCP*/
3829 /* Client should be advanced to, and what the server DHCP response type*/
3830 /* should be. in the client record the specified client record. */
3831 /* */
3832 /* INPUT */
3833 /* */
3834 /* dhcp_ptr Pointer to DHCP Server */
3835 /* client_record_ptr Pointer to DHCP client */
3836 /* */
3837 /* OUTPUT */
3838 /* */
3839 /* NX_SUCCESS Table searched successfully */
3840 /* */
3841 /* CALLS */
3842 /* */
3843 /* _nx_dhcp_update_assignable_ip_address Update IP address status in */
3844 /* the server database */
3845 /* */
3846 /* CALLED BY */
3847 /* */
3848 /* _nx_dhcp_listen_for_messages Listen for, process and respond*/
3849 /* to DHCP Client messages */
3850 /* */
3851 /* RELEASE HISTORY */
3852 /* */
3853 /* DATE NAME DESCRIPTION */
3854 /* */
3855 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3856 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3857 /* resulting in version 6.1 */
3858 /* */
3859 /**************************************************************************/
_nx_dhcp_validate_client_message(NX_DHCP_SERVER * dhcp_ptr,NX_DHCP_CLIENT * dhcp_client_ptr)3860 static UINT _nx_dhcp_validate_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr)
3861 {
3862
3863 ULONG server_ip_address;
3864 UINT iface_index;
3865 NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr;
3866
3867
3868 /* Create a local variable for the client's interface for convenience. */
3869 iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index;
3870 dhcp_interface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[iface_index];
3871
3872 if (dhcp_client_ptr -> nx_dhcp_xid == 0x0)
3873 {
3874
3875 #ifdef EL_PRINTF_ENABLE
3876 EL_PRINTF("DHCPserv: DHCP packet missing transaction ID. Reject the packet silently. \n");
3877 #endif
3878
3879 /* Return the request denied message to clients and return. */
3880 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT;
3881 return(NX_SUCCESS);
3882 }
3883
3884 /* Client messages should never fill in the "Your (Client) IP" or "Next Server IP" fields. */
3885 else if ((dhcp_client_ptr -> nx_dhcp_your_ip_address != NX_DHCP_NO_ADDRESS) ||
3886 (dhcp_client_ptr -> nx_dhcp_clientrec_server_ip != NX_DHCP_NO_ADDRESS))
3887 {
3888
3889 #ifdef EL_PRINTF_ENABLE
3890 EL_PRINTF("DHCPserv: NACK! 'Your IP'/'Server IP' fields should not be filled in.\n");
3891 #endif
3892
3893 /* Return the 'request denied' message to the client. */
3894 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
3895 }
3896
3897 /* Check for missing required fields. */
3898 else if ((dhcp_client_ptr -> nx_dhcp_client_hwtype == 0) ||
3899 (dhcp_client_ptr -> nx_dhcp_client_hwlen == 0))
3900 {
3901
3902 #ifdef EL_PRINTF_ENABLE
3903 EL_PRINTF("DHCPserv: NACK! DHCP packet missing MAC and/or hardware type\n");
3904 #endif
3905
3906 /* Return the request denied message to clients and return. */
3907 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
3908 }
3909
3910 else
3911 {
3912
3913 /* Do validation specific the for message type. This section will also
3914 advance the Client DHCP state and set the server response message type.
3915 */
3916 switch (dhcp_client_ptr -> nx_dhcp_message_type)
3917 {
3918
3919
3920 case NX_DHCP_TYPE_DHCPDISCOVER:
3921 {
3922
3923 #ifdef EL_PRINTF_ENABLE
3924 EL_PRINTF("DHCPserv: Received DISCOVER message\n");
3925 #endif
3926
3927 /* Determine if server needs to assign an IP address based on assigned IP address.
3928 e.g. If this appears to be a retransmission of a previous IP address DISOVERY request,
3929 only assign another IP address if the client appears not to have been assigned one already.*/
3930 /* Initialize response back to be an offer pending validation check. */
3931 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPOFFER;
3932
3933 /* Check for invalid IP address field(s). */
3934 if (dhcp_client_ptr -> nx_dhcp_clientip_address != NX_DHCP_NO_ADDRESS)
3935 {
3936
3937 #ifdef EL_PRINTF_ENABLE
3938 EL_PRINTF("DHCPserv: NACK! Client IP address field must not be filled in.\n");
3939 #endif
3940
3941 /* Let the client know it has an invalid request. */
3942 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
3943 }
3944 else
3945 {
3946
3947 /* DHCP client state advances to SElECTING state. */
3948 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_SELECTING;
3949 }
3950
3951 break;
3952 }
3953
3954 case NX_DHCP_TYPE_DHCPREQUEST:
3955 {
3956
3957
3958 /* This is a more complex message since a client request can be generated from
3959 4 different states: boot, selecting, renew, rebind. This requires that
3960 we determine the Client state based on what's previously known about
3961 the client and which fields are filled in the Request message. */
3962
3963 /* Get the DHCP server IP address for the client package interface. */
3964 server_ip_address = dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address;
3965
3966 /* Get the index of the client packet interface. */
3967 iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index;
3968
3969 /* If the client does not specify a server id but is requesting an IP address... */
3970 if ((dhcp_client_ptr -> nx_dhcp_server_id == 0) &&
3971 (dhcp_client_ptr -> nx_dhcp_requested_ip_address != NX_DHCP_NO_ADDRESS))
3972 {
3973
3974 #ifdef EL_PRINTF_ENABLE
3975 EL_PRINTF("DHCPserv: Received REQUEST (BOOT state) message\n");
3976 #endif
3977 /* ...Then it is in the boot state as per RFC 2131 4.3.2 (requests
3978 an IP address but is skipping the DISCO message). */
3979
3980 /* This client may NOT specify a Client IP address e.g. that field must
3981 be left blank. */
3982 if (dhcp_client_ptr -> nx_dhcp_clientip_address != NX_DHCP_NO_ADDRESS)
3983 {
3984
3985 #ifdef EL_PRINTF_ENABLE
3986 EL_PRINTF("DHCPserv: NACK! REQUEST message may not specify Client IP address.\n");
3987 #endif
3988
3989 /* Let the client know it has an invalid request. */
3990 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
3991 break;
3992 }
3993
3994 /* Server SHOULD send a DHCPNAK message to the client if the 'requested IP address' is incorrect, or is on the wrong network.
3995 RFC 2131, Section 4.3.2, Page31. */
3996 if ((dhcp_client_ptr -> nx_dhcp_assigned_ip_address != 0) &&
3997 (dhcp_client_ptr -> nx_dhcp_assigned_ip_address != dhcp_client_ptr -> nx_dhcp_requested_ip_address))
3998 {
3999
4000 ULONG ip_address_assigned = dhcp_client_ptr -> nx_dhcp_assigned_ip_address;
4001
4002 #ifdef EL_PRINTF_ENABLE
4003 EL_PRINTF("DHCPserv: NACK! REQUEST message contains incorrect requested IP address. \n");
4004 #endif
4005
4006 /* No; invalid request. Return the IP address tentatively assigned to
4007 the client back to the available IP address pool. */
4008
4009 _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, ip_address_assigned,
4010 NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE);
4011
4012 /* Clear requested IP lease time because the client is not granted an IP address lease. */
4013 dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0;
4014
4015 /* Let the client know it made an invalid request. */
4016 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4017 break;
4018 }
4019
4020 /* Set the client state to the BOOT state */
4021 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_BOOT;
4022
4023 /* Indicate the server will grant the IP lease. */
4024 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK;
4025
4026 /* Advance the client state to requesting (waiting for an ACK). */
4027 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_REQUESTING;
4028 break;
4029 }
4030 /* Else if the client is specifying a server id, and a requested IP address... */
4031 else if (dhcp_client_ptr -> nx_dhcp_server_id &&
4032 (dhcp_client_ptr -> nx_dhcp_requested_ip_address != NX_DHCP_NO_ADDRESS))
4033 {
4034
4035 #ifdef EL_PRINTF_ENABLE
4036 EL_PRINTF("DHCPserv: Received REQUEST (SELECT state) message\n");
4037 #endif
4038
4039 /* ...Then the client is in the SELECT state as per RFC 2131 4.3.2 (sent a
4040 DISCOVERY message and is responding to a server OFFER message). */
4041
4042 /* Client may NOT specify a Client IP address. */
4043 if (dhcp_client_ptr -> nx_dhcp_clientip_address != NX_DHCP_NO_ADDRESS)
4044 {
4045
4046 #ifdef EL_PRINTF_ENABLE
4047 EL_PRINTF("DHCPserv: NACK! REQUEST message may not specify Client IP address.\n");
4048 #endif
4049
4050 /* Let the client know it has an invalid request. */
4051 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4052 break;
4053 }
4054
4055 /* Check if the Client has chosen this server's offer (e.g.server ID option in the
4056 REQUEST message). */
4057 if (dhcp_client_ptr -> nx_dhcp_server_id != server_ip_address)
4058 {
4059
4060 ULONG ip_address_assigned;
4061
4062 /* We are not. */
4063
4064 /* Is the Client accepting the same IP address this server offered? */
4065 if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == dhcp_client_ptr -> nx_dhcp_requested_ip_address)
4066 {
4067
4068 /* Yes, so do not change the client record IP address and IP address
4069 status in the server interface table as assigned. */
4070 ip_address_assigned = dhcp_client_ptr -> nx_dhcp_assigned_ip_address;
4071 }
4072 else
4073 {
4074
4075 /* No, it is accepting a different IP address from another server. */
4076 ip_address_assigned = dhcp_client_ptr -> nx_dhcp_requested_ip_address;
4077
4078 /* So update the client record's assigned address to the one it is accepting
4079 from another server. */
4080 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_requested_ip_address;
4081 }
4082
4083 /* Update the server interface table with the information. */
4084 _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, ip_address_assigned,
4085 NX_DHCP_ADDRESS_STATUS_ASSIGNED_OTHER);
4086
4087 #ifdef EL_PRINTF_ENABLE
4088 EL_PRINTF("DHCPserv: SILENCE! REQUEST message indicates Client accepting another server IP.\n");
4089 #endif
4090
4091 /* If this client wants an IP address from this server it must start
4092 over at the init state. */
4093 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
4094
4095 /* No need to respond. */
4096 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT;
4097
4098 return(NX_SUCCESS);
4099 }
4100
4101 /* Make sure the Client did in fact receive an OFFER from this server (e.g. has
4102 been tentatively assigned an IP address from us). */
4103 if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS)
4104 {
4105
4106 #ifdef EL_PRINTF_ENABLE
4107 EL_PRINTF("DHCPserv: NACK! REQUEST message does not indicate valid assigned IP address.\n");
4108 #endif
4109
4110 /* It did not. This is an invalid request. Let the client know. */
4111 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4112
4113 /* Clear requested IP lease times because the client was not assigned an IP address. */
4114 dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0;
4115
4116 /* Nothing more to do! */
4117 break;
4118 }
4119
4120 /* Does the Client's requested IP address match the "Your IP" field in the server OFFER
4121 previously sent to this client (e.g. Client's assigned IP address)? */
4122 else if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address != dhcp_client_ptr -> nx_dhcp_requested_ip_address)
4123 {
4124
4125 ULONG ip_address_assigned = dhcp_client_ptr -> nx_dhcp_assigned_ip_address;
4126
4127 #ifdef EL_PRINTF_ENABLE
4128 EL_PRINTF("DHCPserv: NACK! REQUEST message contains requested IP address. \n");
4129 #endif
4130
4131 /* No; invalid request. Return the IP address tentatively assigned to
4132 the client back to the available IP address pool. */
4133
4134 _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, ip_address_assigned,
4135 NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE);
4136
4137 /* Clear requested IP lease time because the client is not granted an IP address lease. */
4138 dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0;
4139
4140 /* Let the client know it made an invalid request. */
4141 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4142 break;
4143 }
4144
4145 /* The Client accepts this Server's offer. We will grant the client the IP lease now. */
4146 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK;
4147
4148 /* UPdate the client state to REQUESTING (waiting on an ACK). */
4149 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_REQUESTING;
4150 }
4151
4152 /* Is this a RENEW or REBIND request? If so the server ID and requested IP options must
4153 NOT be filled in as per RFC 2131 4.3.2. */
4154 else if ((dhcp_client_ptr -> nx_dhcp_server_id == NX_DHCP_NO_ADDRESS) &&
4155 (dhcp_client_ptr -> nx_dhcp_requested_ip_address == NX_DHCP_NO_ADDRESS))
4156 {
4157
4158 #ifdef EL_PRINTF_ENABLE
4159 EL_PRINTF("DHCPserv: Received REQUEST (RENEW/REBIND state) message\n");
4160 #endif
4161
4162 /* Yes, this is a renew/rebind request! */
4163
4164 /* Extending an IP lease is a administration decision vs RFC mandate. The
4165 NetX DHCP Server automatically extends IP leases. */
4166
4167 /* Go ahead and ACK the renew request pending any DHCP violations. */
4168 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK;
4169
4170 /* The "Client IP" address field MUST be filled in. */
4171 if (dhcp_client_ptr -> nx_dhcp_clientip_address == NX_DHCP_NO_ADDRESS)
4172 {
4173
4174 #ifdef EL_PRINTF_ENABLE
4175 EL_PRINTF("DHCPserv: NACK! REQUEST message no 'Client IP' address specified. \n");
4176 #endif
4177
4178 /* This is an invalid renew/rebind request. Reject the request but
4179 do not change or advance the Client state (SHOULD be bound). */
4180 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4181
4182 break;
4183 }
4184
4185 /* The "Client IP" address subnet should match the Client packet source IP address subnet. */
4186 if ((dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_client_ptr -> nx_dhcp_clientip_address) !=
4187 (dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_interface_table_ptr -> nx_dhcp_server_ip_address))
4188 {
4189 #ifdef EL_PRINTF_ENABLE
4190 EL_PRINTF("DHCPserv: NACK! REQUEST message; the 'Client IP' address subnet does not match the DHCP server subnet. \n");
4191 #endif
4192
4193 /* This is an invalid renew/rebind request. Reject the request but
4194 do not change or advance the Client state (SHOULD be bound). */
4195 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4196 break;
4197 }
4198
4199 /* Is there an assigned IP address in the Client record? */
4200 if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS)
4201 {
4202
4203 #ifdef EL_PRINTF_ENABLE
4204 EL_PRINTF("DHCPserv: NACK! REQUEST message; server has no record of assigned IP address.\n");
4205 #endif
4206
4207 /* No; possibly assigned by another DHCP server or outside of DHCP protocol.
4208 Reject the renewal request. */
4209 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4210
4211 /* This client needs to start the configuration process with this
4212 server from the INIT start if it wants an IP address from it. */
4213 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
4214 break;
4215 }
4216
4217 /* Determine if this is a renew or a rebind request. */
4218 if (dhcp_client_ptr -> nx_dhcp_destination_ip_address != NX_DHCP_BC_ADDRESS)
4219 {
4220
4221 #ifdef EL_PRINTF_ENABLE
4222 EL_PRINTF("DHCPserv: Received REQUEST (renewing) message\n");
4223 #endif
4224
4225 /* Renewing: DHCP clients' renew requests must be unicast. */
4226 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_RENEWING;
4227 }
4228 else
4229 {
4230
4231 #ifdef EL_PRINTF_ENABLE
4232 EL_PRINTF("DHCPserv: Received REQUEST (rebinding) message\n");
4233 #endif
4234
4235 /* Rebinding DHCP clients' rebind request must be broadcast. */
4236 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_REBINDING;
4237 }
4238 }
4239 else
4240 {
4241
4242 #ifdef EL_PRINTF_ENABLE
4243 EL_PRINTF("DHCPserv: NACK! Received unknown REQUEST message type.\n");
4244 #endif
4245
4246 /* Do not respond to unknown requests. This is kind of a dealer's choice
4247 because it is not specified in the RFC 2132 how to handle undefined
4248 request IDs or message types. */
4249 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT;
4250 return(NX_SUCCESS);
4251 }
4252
4253 break;
4254 }
4255
4256 case NX_DHCP_TYPE_DHCPRELEASE:
4257 {
4258
4259 #ifdef EL_PRINTF_ENABLE
4260 EL_PRINTF("DHCPserv: Received RELEASE response type.\n");
4261 #endif
4262
4263
4264 /* The Client is releasing it's IP address back to the server. A client is not
4265 required to do this; usually it indicates the client may have moved on the
4266 network.
4267
4268 Clear the client record and mark the IP address as available. If the request proves
4269 invalid, this server will ignore it and let the Client's assigned IP lease expire. */
4270
4271 /* Regardless what happens the server does not send a reply to a RELEASE message. */
4272 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT;
4273
4274 /* Was an address previously assigned? */
4275 if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS)
4276 {
4277
4278 /* No; nothing to do here. */
4279 return(NX_SUCCESS);
4280 }
4281
4282 /* The client IP field must be filled in for RELEASE requests. Was it? */
4283 if (dhcp_client_ptr -> nx_dhcp_clientip_address == NX_DHCP_NO_ADDRESS)
4284 {
4285
4286 /* No; This is an invalid release request. */
4287 return(NX_SUCCESS);
4288 }
4289
4290 /* Does client IP field match what this Server assigned the Client? */
4291 if (dhcp_client_ptr -> nx_dhcp_clientip_address != dhcp_client_ptr -> nx_dhcp_assigned_ip_address)
4292 {
4293
4294 /* No; Not sure how this happened but let the existing assigned
4295 IP address lease expire. Ignore this message. */
4296 return(NX_SUCCESS);
4297 }
4298
4299 /* A RELEASE request must be unicasted to the server. Was this a broadcast
4300 message? */
4301 if (dhcp_client_ptr -> nx_dhcp_destination_ip_address == NX_DHCP_BC_ADDRESS)
4302 {
4303
4304 /* Yes, so not a valid RELEASE request. */
4305 return(NX_SUCCESS);
4306 }
4307 else
4308 {
4309
4310 UINT index = dhcp_client_ptr -> nx_dhcp_client_iface_index;
4311 ULONG server_ip = (&dhcp_ptr -> nx_dhcp_interface_table[index]) ->nx_dhcp_server_ip_address;
4312
4313 /* Check that we are the intended server. */
4314 if (dhcp_client_ptr -> nx_dhcp_destination_ip_address != server_ip)
4315 {
4316
4317 /* We are not. Not a valid Release request. */
4318 return(NX_SUCCESS);
4319 }
4320 }
4321
4322 /* Legitimate release request: return the IP address to the available pool,
4323 and clear the client session. */
4324
4325 /* Release the client's assigned IP address (in the "CI-ADDR" field). */
4326 _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr,
4327 dhcp_client_ptr -> nx_dhcp_assigned_ip_address,
4328 NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE);
4329
4330 /* Clear the Client's assigned IP address. */
4331 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS;
4332
4333 /* If this client wants to configure its network parameters with us it
4334 must start at the INIT state. */
4335 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
4336
4337
4338 break;
4339 }
4340
4341 case NX_DHCP_TYPE_DHCPDECLINE:
4342 {
4343
4344 #ifdef EL_PRINTF_ENABLE
4345 EL_PRINTF("DHCPserv: Received DECLINE response type.\n");
4346 #endif
4347
4348 /* The Client is informing us an IP address we assigned to it is apparently already
4349 in use by another host. It needs to restart in the INIT/BOOT state for this
4350 server to assign it another IP address. */
4351 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
4352
4353 /* Regardless what happens do not send a reply. */
4354 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT;
4355
4356 /* If no address previously assigned, silently ignore this message. */
4357 if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS)
4358 {
4359
4360 /* This client never had an address assigned by this server. Do nothing. */
4361 return(NX_SUCCESS);
4362 }
4363
4364 /* A DECLINE message must specify the requested address. */
4365 if (dhcp_client_ptr -> nx_dhcp_requested_ip_address == NX_DHCP_NO_ADDRESS)
4366 {
4367
4368 /* This is an invalid decline request. Reject it silently. */
4369 return(NX_SUCCESS);
4370 }
4371
4372 /* A Decline request is supposed to be unicasted to the server. If it is not,
4373 ignore it. */
4374 if (dhcp_client_ptr -> nx_dhcp_destination_ip_address != NX_DHCP_BC_ADDRESS)
4375 {
4376
4377 return(NX_SUCCESS);
4378 }
4379 else
4380 {
4381
4382 UINT index = dhcp_client_ptr -> nx_dhcp_client_iface_index;
4383 ULONG server_ip = (&dhcp_ptr -> nx_dhcp_interface_table[index]) ->nx_dhcp_server_ip_address;
4384
4385 /* Check that we are the intended server. */
4386 if (dhcp_client_ptr -> nx_dhcp_server_id != server_ip)
4387 {
4388
4389 /* We are not. Ignore the request. */
4390 return(NX_SUCCESS);
4391 }
4392 }
4393
4394 /* Release the client's assigned IP address. */
4395 _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr,
4396 dhcp_client_ptr -> nx_dhcp_assigned_ip_address,
4397 NX_DHCP_ADDRESS_STATUS_ASSIGNED_OTHER);
4398
4399 /* Clear the Client's assigned IP address. */
4400 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS;
4401
4402 break;
4403 }
4404
4405 case NX_DHCP_TYPE_DHCPINFORM:
4406 {
4407
4408 #ifdef EL_PRINTF_ENABLE
4409 EL_PRINTF("DHCPserv: Received INFORM response type.\n");
4410 #endif
4411
4412
4413 /* A DHCP client sends an INFORM message when it has been assigned an IP address
4414 with another server or outside DHCP but still needs local configuration data.
4415 The DHCP server must update its database with their address (specified in the "CI-ADDR" field)
4416 as no longer available. When the server forms a reply ACK, it must leave the
4417 'Your IP' and lease time fields blank as per RFC 2131 3.4. */
4418
4419
4420 /* A DHCP server must respond (ACK) to INFORM messages unless the message
4421 is invalid. */
4422 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK;
4423
4424 /* The INFORM message must have the Client IP address filled in to be valid. */
4425 if (dhcp_client_ptr -> nx_dhcp_clientip_address == NX_DHCP_NO_ADDRESS)
4426 {
4427
4428 /* Invalid message. */
4429 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4430 }
4431
4432 /* It cannot have a requested IP option in the options. */
4433 if (dhcp_client_ptr -> nx_dhcp_requested_ip_address != NX_DHCP_NO_ADDRESS)
4434 {
4435
4436 /* Invalid message. */
4437 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4438 }
4439
4440 /* Make sure the server interface table is up to date for this IP address. */
4441 _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, dhcp_client_ptr -> nx_dhcp_clientip_address,
4442 NX_DHCP_ADDRESS_STATUS_ASSIGNED_EXT);
4443
4444 /* And update the client record assigned IP address in case it is not set yet. */
4445 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_clientip_address;
4446
4447 /* Has client IP address leased (bound) from this server? */
4448 if (dhcp_client_ptr -> nx_dhcp_client_state != NX_DHCP_STATE_BOUND)
4449 {
4450
4451 /* No, so if this client needs to configure an IP address assigned
4452 with this server it must start at the INIT state. */
4453 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
4454 }
4455
4456 break;
4457 }
4458 default:
4459 {
4460
4461 #ifdef EL_PRINTF_ENABLE
4462 EL_PRINTF("DHCPserv: NACK! Received unknown response type.\n");
4463 #endif
4464
4465 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT;
4466
4467 return(NX_SUCCESS);
4468
4469 /* No further processing to do. Leave the client state unchanged, whatever it was/is. */
4470 }
4471
4472 } /* switch case on client message*/
4473 }
4474
4475 /* Were there were any conditions requiring a NACK response? */
4476 if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPNACK)
4477 {
4478 /* Yes, the caller knows to send the NACK message. No processing to do. */
4479 return NX_SUCCESS;
4480 }
4481
4482 /* If this is not a DISCOVERY or REQUEST message, we are done! */
4483 if ((dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPDISCOVER) &&
4484 (dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPREQUEST))
4485 {
4486
4487 return(NX_SUCCESS);
4488 }
4489
4490 /* If the boot/init state client did not request an address, we are done. */
4491 if (dhcp_client_ptr -> nx_dhcp_requested_ip_address == NX_DHCP_NO_ADDRESS)
4492 {
4493
4494 return(NX_SUCCESS);
4495 }
4496
4497 /* Check if the Client has requested a valid IP address. This is only permitted
4498 with a DISCO or REQUEST messages while the Client is in either the BOOT/INIT
4499 or SELECT states.
4500
4501 As per RFC 2131 4.3.1, the DHCP server should assign an IP address in order of preference as follows:
4502 1) the client currently is bound to
4503 2) client ip address in client records (e.g. previously assigned to)
4504 3) the currently requested IP
4505 4) the server will assign one. */
4506
4507 /* Find the currently binding source address in the server's database. */
4508 if (dhcp_client_ptr -> nx_dhcp_source_ip_address != NX_DHCP_NO_ADDRESS)
4509 {
4510
4511 /* Assign this as the Client's IP address. */
4512 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_source_ip_address;
4513 }
4514
4515 /* Next best option: Has the client previously been assigned an IP address? */
4516 else if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address)
4517 {
4518
4519 /* Yes, let's leave it assigned to it. */
4520 return(NX_SUCCESS);
4521 }
4522 else
4523 {
4524
4525 /* Last option: Set the client's requested IP address as the one to assign. */
4526 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_requested_ip_address;
4527 }
4528
4529 return(NX_SUCCESS);
4530 }
4531
4532
4533 /**************************************************************************/
4534 /* */
4535 /* FUNCTION RELEASE */
4536 /* */
4537 /* _nx_dhcp_server_assign_ip_address PORTABLE C */
4538 /* 6.1 */
4539 /* AUTHOR */
4540 /* */
4541 /* Yuxin Zhou, Microsoft Corporation */
4542 /* */
4543 /* DESCRIPTION */
4544 /* */
4545 /* This service finds an available IP address for the client if none is */
4546 /* provided, and updates the client's record with the new IP address. It */
4547 /* updates the interface table entry with current client data (lease */
4548 /* time, owner). */
4549 /* */
4550 /* If there already is an assigned IP address on the client record, this */
4551 /* function will verify the IP address has not been assigned to another */
4552 /* client before setting the current client as owner. If it has, this */
4553 /* function will look for another available IP address for the client. */
4554 /* */
4555 /* Once an address is assigned, this function updates the fields in the */
4556 /* interface pointer entry, and the "Your IP address" in its message back*/
4557 /* to the client. */
4558 /* */
4559 /* INPUT */
4560 /* */
4561 /* dhcp_cptr Pointer to DHCP Server */
4562 /* dhcp_client_ptr Pointer to client record */
4563 /* */
4564 /* OUTPUT */
4565 /* */
4566 /* NX_SUCCESS Successful completion */
4567 /* NX_DHCP_NO_AVAILABLE_IP_ADDRESSES No available address to assign*/
4568 /* */
4569 /* CALLS */
4570 /* */
4571 /* _nx_dhcp_find_interface_table_ip_address */
4572 /* Look up IP address in */
4573 /* server interface table */
4574 /* _nx_dhcp_find_ip_address_owner Look up owner of an IP address*/
4575 /* in server interfce table */
4576 /* _nx_dhcp_record_ip_address_owner Set the client as IP address */
4577 /* owner in interface table */
4578 /* */
4579 /* CALLED BY */
4580 /* */
4581 /* _nx_dhcp_validate_client_message Check Client DHCP messages for*/
4582 /* proper data and determine */
4583 /* server response */
4584 /* */
4585 /* RELEASE HISTORY */
4586 /* */
4587 /* DATE NAME DESCRIPTION */
4588 /* */
4589 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4590 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4591 /* resulting in version 6.1 */
4592 /* */
4593 /**************************************************************************/
_nx_dhcp_server_assign_ip_address(NX_DHCP_SERVER * dhcp_ptr,NX_DHCP_CLIENT * dhcp_client_ptr)4594 static UINT _nx_dhcp_server_assign_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr)
4595 {
4596
4597 NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr;
4598 NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr;
4599 UINT assigned_to_client;
4600 UINT assigned_ip;
4601 UINT lease_time;
4602
4603
4604 /* Set a flag on the outcome of finding an available address. */
4605 assigned_ip = NX_FALSE;
4606
4607 /* Compute the client lease time based on client's requested
4608 lease time and server default lease time. */
4609 lease_time = dhcp_client_ptr -> nx_dhcp_requested_lease_time;
4610
4611
4612 #if (NX_DHCP_DEFAULT_LEASE_TIME >= 0xFFFFFFFF)
4613 if (lease_time == 0)
4614 #else
4615 if ((lease_time == 0) || (lease_time > NX_DHCP_DEFAULT_LEASE_TIME))
4616 #endif
4617 {
4618 lease_time = NX_DHCP_DEFAULT_LEASE_TIME;
4619 }
4620
4621
4622 interface_address_ptr = (NX_DHCP_INTERFACE_IP_ADDRESS *)NX_NULL;
4623
4624 /* Does the Client have a candidate already assigned? */
4625 if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address)
4626 {
4627
4628 /* The client does have one assigned, but we need to verify it is available
4629 or already assigned to the client. */
4630
4631 /* Look for this IP address in the specified interface IP address list (table). */
4632 _nx_dhcp_find_interface_table_ip_address(dhcp_ptr, dhcp_client_ptr -> nx_dhcp_client_iface_index,
4633 dhcp_client_ptr -> nx_dhcp_assigned_ip_address, &interface_address_ptr);
4634
4635 /* Was the ip address found? */
4636 if (interface_address_ptr)
4637 {
4638
4639 /* Yes; Is it assigned to anyone yet? */
4640 if (interface_address_ptr -> assigned == NX_FALSE)
4641 {
4642 /* No, We will assign this one further below. */
4643 }
4644 else
4645 {
4646
4647 /* Determine who if is assigned to. */
4648 _nx_dhcp_find_ip_address_owner(interface_address_ptr, dhcp_client_ptr, &assigned_to_client);
4649
4650 /* Assigned to this client? */
4651 if (assigned_to_client)
4652 {
4653
4654
4655 /* Yes, so we're done here, except for checking a few fields. */
4656
4657 /* Renew the lease time. */
4658 interface_address_ptr -> lease_time = lease_time;
4659
4660 /* Set the Your IP address field for the server response message. */
4661 dhcp_client_ptr -> nx_dhcp_your_ip_address = interface_address_ptr -> nx_assignable_ip_address;
4662
4663 return(NX_SUCCESS);
4664 }
4665
4666 #ifdef EL_PRINTF_ENABLE
4667 EL_PRINTF("DHCPserv: NACK! Cannot assign requested IP address (already assigned)\n");
4668 #endif
4669
4670 /* No, assigned to someone else. We cannot provide this so return a NACK. */
4671 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4672 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
4673
4674 /* Clear the client's assigned IP address since it is assigned to someone else. */
4675 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS;
4676
4677 return(NX_SUCCESS);
4678 }
4679 }
4680 else
4681 {
4682
4683 /* If this is a NOT discovery message, the server can not very well
4684 assign a different IP address becaause an ACK reply cannot contain
4685 different information. */
4686 if (dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPDISCOVER)
4687 {
4688
4689 #ifdef EL_PRINTF_ENABLE
4690 EL_PRINTF("DHCPserv: NACK! Cannot assign requested IP address (not owned by server)\n");
4691 #endif
4692
4693 /* Apparently the client has asked for an IP address either not
4694 in the server database or on another network. We cannot provide this
4695 so return a NACK. */
4696 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4697 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
4698
4699 /* Clear the client record's 'assigned' IP address since none was assigned. */
4700 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS;
4701
4702 /* Since the client did not get assigned an IP address
4703 make sure the requested lease time is reset to zero. */
4704 dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0;
4705
4706 return(NX_SUCCESS);
4707 }
4708
4709 /* For a Discovery request, the server will go ahead and find an
4710 available IP address to offer the client. */
4711 }
4712 }
4713
4714 /* If the client doesn't have an address assigned yet, find one in the server table not
4715 yet assigned. */
4716 if (interface_address_ptr == 0x0)
4717 {
4718
4719 UINT i;
4720
4721 /* Set a local varible to the IP address list for this client. */
4722 dhcp_interface_table_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[dhcp_client_ptr -> nx_dhcp_client_iface_index]);
4723
4724 /* Yes, search for an available ip address in the IP list for this interface */
4725 for(i = 0; i < dhcp_interface_table_ptr -> nx_dhcp_address_list_size; i++)
4726 {
4727
4728 /* Set a local pointer variable to the next address. */
4729 interface_address_ptr = &dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i];
4730
4731 /* Is this address assigned already? */
4732 if (interface_address_ptr -> assigned == NX_FALSE)
4733 {
4734
4735 /* No, but it is now! */
4736
4737 /* Indicate the search was successful. */
4738 assigned_ip = NX_TRUE;
4739
4740 break;
4741 }
4742 }
4743
4744 /* Check if we were able to find an available IP address. */
4745 if (assigned_ip == NX_FALSE)
4746 {
4747
4748 #ifdef EL_PRINTF_ENABLE
4749 EL_PRINTF("DHCPserv: NACK! Cannot assign requested IP address (not found in server IP list)\n");
4750 #endif
4751
4752
4753 /* The server is not obliged to respond, but it should let the client
4754 know if it cannot provide what it requests. */
4755 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
4756 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4757
4758 /* Since the client did not get assigned an IP address
4759 make sure the requested lease time is reset to zero. */
4760 dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0;
4761
4762 /* Make sure the client record's 'assigned' IP address ir removed since it was not assigned. */
4763 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS;
4764
4765 /* No, return the error status. */
4766 return(NX_DHCP_NO_AVAILABLE_IP_ADDRESSES);
4767 }
4768 }
4769
4770 /* Was the assigned ip address available? */
4771 if (interface_address_ptr)
4772 {
4773
4774 /* Set the client as the IP address owner in the server interface table. */
4775 _nx_dhcp_record_ip_address_owner(interface_address_ptr, dhcp_client_ptr, lease_time);
4776
4777 /* Set the client's assigned IP address. */
4778 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = interface_address_ptr -> nx_assignable_ip_address;
4779
4780 /* Set the Your IP address field for the server response message. */
4781 dhcp_client_ptr -> nx_dhcp_your_ip_address = interface_address_ptr -> nx_assignable_ip_address;
4782
4783 /* We are done! */
4784 return(NX_SUCCESS);
4785 }
4786
4787 /* If we're here we were not able to assign an IP address. */
4788
4789 /* The server is not obliged to respond, but it should let the client
4790 know if it cannot provide what it requests. */
4791 dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT;
4792
4793 #ifdef EL_PRINTF_ENABLE
4794 EL_PRINTF("DHCPserv: NACK! Server cannot assign requested IP address\n");
4795 #endif
4796
4797 dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK;
4798
4799 /* Make sure the client record's 'assigned' IP address ir removed since it was not assigned. */
4800 dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS;
4801
4802 /* Since the client did not get assigned an IP address
4803 make sure the requested lease time is reset to zero. */
4804 dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0;
4805
4806 return(NX_DHCP_NO_AVAILABLE_IP_ADDRESSES);
4807 }
4808
4809
4810 /**************************************************************************/
4811 /* */
4812 /* FUNCTION RELEASE */
4813 /* */
4814 /* _nx_dhcp_server_extract_information PORTABLE C */
4815 /* 6.1 */
4816 /* AUTHOR */
4817 /* */
4818 /* Yuxin Zhou, Microsoft Corporation */
4819 /* */
4820 /* DESCRIPTION */
4821 /* */
4822 /* This function extracts information from a DHCP Client packet and */
4823 /* updates the server's client database. If no client record exists for*/
4824 /* the client this function will create one for it. It does some */
4825 /* message validation but primary extracts DHCP header and option */
4826 /* fields to the client record. */
4827 /* */
4828 /* If an internal error is encountered parsing the packet buffer, this */
4829 /* function returns the error status. If it finds the client DHCP */
4830 /* message invalid, it returns successful completion but sets the DHCP */
4831 /* server to respond with either NACK or silence. */
4832 /* */
4833 /* When this function is finished, the caller releases the packet. */
4834 /* */
4835 /* INPUT */
4836 /* */
4837 /* dhcp_cptr Pointer to DHCP Server */
4838 /* dhcp_client_ptr Pointer to client record */
4839 /* packet_ptr Pointer to DHCP client packet */
4840 /* iface_index Interface index packet was */
4841 /* received on */
4842 /* */
4843 /* OUTPUT */
4844 /* */
4845 /* NX_SUCCESS Successful completion */
4846 /* status Actual completion status */
4847 /* */
4848 /* CALLS */
4849 /* */
4850 /* _nx_dhcp_find_client_record_by_chaddr Find Client record using the */
4851 /* parsed mac address */
4852 /* _nx_dhcp_server_get_data Parse DHCP data from buffer */
4853 /* */
4854 /* CALLED BY */
4855 /* */
4856 /* _nx_dhcp_listen_for_messages Process DHCP Client messages */
4857 /* */
4858 /* RELEASE HISTORY */
4859 /* */
4860 /* DATE NAME DESCRIPTION */
4861 /* */
4862 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4863 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
4864 /* fixed the issue of read */
4865 /* and write overflow, */
4866 /* fixed compiler warnings, */
4867 /* resulting in version 6.1 */
4868 /* */
4869 /**************************************************************************/
_nx_dhcp_server_extract_information(NX_DHCP_SERVER * dhcp_ptr,NX_DHCP_CLIENT ** dhcp_client_ptr,NX_PACKET * packet_ptr,UINT iface_index)4870 static UINT _nx_dhcp_server_extract_information(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr,
4871 NX_PACKET *packet_ptr, UINT iface_index)
4872 {
4873
4874 UINT status;
4875 ULONG value;
4876 UINT size = 0;
4877 ULONG xid;
4878 UCHAR *work_ptr;
4879 ULONG client_mac_msw;
4880 ULONG client_mac_lsw;
4881 NX_IPV4_HEADER *ip_header_ptr;
4882 NX_DHCP_CLIENT *temp_client_rec_ptr;
4883
4884
4885 /* Initialize the DHCP Client pointer to null pending successful data extraction. */
4886 *dhcp_client_ptr = NX_NULL;
4887
4888 /* Set up UCHAR pointer to HW address field to extract client hardware address
4889 which we will use as the client's unique identifier, since not all clients may use
4890 Option 61/Client Identifier. */
4891 work_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_CLIENT_HW;
4892
4893 /* Pickup the MSW of the MAC address. */
4894 client_mac_msw = (((ULONG) work_ptr[0]) << 8) | ((ULONG) work_ptr[1]);
4895 client_mac_lsw = (((ULONG) work_ptr[2]) << 24) |
4896 (((ULONG) work_ptr[3]) << 16) |
4897 (((ULONG) work_ptr[4]) << 8) |
4898 ((ULONG) work_ptr[5]);
4899
4900 /* Check the client hardware (mac address) field is filled in. */
4901 if ((client_mac_msw == 0) && (client_mac_lsw == 0))
4902 {
4903
4904 return(NX_DHCP_INVALID_HW_ADDRESS);
4905 }
4906
4907 /* Look up the client record by IP address and interface index in Client Records table. */
4908 status = _nx_dhcp_find_client_record_by_chaddr(dhcp_ptr, iface_index, client_mac_msw,
4909 client_mac_lsw, &temp_client_rec_ptr, NX_TRUE);
4910
4911
4912 /* Check for error during search. */
4913 if ((status != NX_SUCCESS) || !temp_client_rec_ptr)
4914 {
4915 return(status);
4916 }
4917
4918
4919 /* Note: No need to check for NULL pointer because we asked to add the
4920 record if no match is found. */
4921
4922
4923 /* Get the client's current binding IP address from the packet interface. */
4924 ip_header_ptr = (NX_IPV4_HEADER *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV4_HEADER));
4925
4926 temp_client_rec_ptr -> nx_dhcp_source_ip_address = ip_header_ptr -> nx_ip_header_source_ip;
4927 temp_client_rec_ptr -> nx_dhcp_destination_ip_address = ip_header_ptr -> nx_ip_header_destination_ip;
4928
4929 /* Get the message type. */
4930 status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_OP, 1, &value);
4931 if (status)
4932 {
4933 return(status);
4934 }
4935
4936 /* Check this is a 'request' DHCP Client message (not to be confused with the REQUEST
4937 message type. */
4938 if (value != NX_DHCP_OP_REQUEST)
4939 {
4940
4941 #ifdef EL_PRINTF_ENABLE
4942 EL_PRINTF("DHCPserv: SILENCE! Client DHCP packet not coded as a BOOT Request. Invalid request.\n");
4943 #endif
4944
4945 /* Set the server to ignore the 'reply'. */
4946 temp_client_rec_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT;
4947
4948 /* Return successful completion status. */
4949 return(NX_SUCCESS);
4950 }
4951
4952 /* Get the hardware type. */
4953 status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_HTYPE, 1, &value);
4954 if (status)
4955 {
4956 return(status);
4957 }
4958
4959 /* This is the Client interface type which is used in the default client identifier tag. */
4960 temp_client_rec_ptr -> nx_dhcp_client_hwtype = value;
4961
4962 /* Get the hardware length. */
4963 status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_HLEN, 1, &value);
4964 if (status)
4965 {
4966 return(status);
4967 }
4968
4969 /* This is the size of the hardware address. Used in the default client identifier tag. */
4970 temp_client_rec_ptr -> nx_dhcp_client_hwlen = value;
4971
4972 /* Extract the message ID. */
4973 status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_XID, 4, &xid);
4974 if (status)
4975 {
4976 return(status);
4977 }
4978
4979 /* Save the client xid to use in the server's reply back. */
4980 temp_client_rec_ptr -> nx_dhcp_xid = xid;
4981
4982 /* Check if response to client should unicast or (default) broadcast. */
4983 status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_FLAGS, 1, &value);
4984 if (status)
4985 {
4986 return(status);
4987 }
4988
4989 /* Get the Client's preference for unicast vs broadcast. */
4990 temp_client_rec_ptr -> nx_dhcp_broadcast_flag_set = (value & NX_DHCP_FLAGS_BROADCAST) ? 0x80 : 0x0;
4991
4992 /* Extract the Requested Client IP address, if there is one. */
4993 status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_CLIENT_IP, 4, &value);
4994 if (status)
4995 {
4996 return(status);
4997 }
4998
4999 /* This is the Client IP address reported by the Client. */
5000 temp_client_rec_ptr -> nx_dhcp_clientip_address = value;
5001
5002 /* Update the IP address assigned to the Client "Your/client IP address". */
5003 status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_YOUR_IP, 4, &value);
5004 if (status)
5005 {
5006 return(status);
5007 }
5008
5009 /* This is the "Your IP address" which only the server should fill in. Should be zero in
5010 client messages. */
5011 temp_client_rec_ptr -> nx_dhcp_your_ip_address = value;
5012
5013 /* Extract the "Next Server IP address". */
5014 status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_SERVER_IP, 4, &value);
5015 if (status)
5016 {
5017 return(status);
5018 }
5019 temp_client_rec_ptr -> nx_dhcp_clientrec_server_ip = value;
5020
5021 /* Store relay IP address for DHCP server (on another subnet) if there is one. */
5022 status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_RELAY_IP, 4, &value);
5023 if (status)
5024 {
5025 return(status);
5026 }
5027 temp_client_rec_ptr -> nx_dhcp_relay_ip_address = value;
5028
5029 /* Look for the marker indicating option data (magic cookie). */
5030 status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_VENDOR, 4, &value);
5031 if (status)
5032 {
5033 return(status);
5034 }
5035
5036 /* Note we don't store the magic cookie value. */
5037
5038 /* Are there user options? */
5039 if (value == NX_DHCP_MAGIC_COOKIE)
5040 {
5041 /* Yes there are user options in the Client message. */
5042
5043 /* Move up the buffer pointer past the magic cookie thing. */
5044 work_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_VENDOR + 4;
5045
5046 /* Extract all the client option data. */
5047 while (*work_ptr != 0xFF)
5048 {
5049
5050 /* Guard against a missing "END" marker by checking if we are at the end of the DHCP packet data. */
5051 if (work_ptr + 2 > packet_ptr -> nx_packet_append_ptr)
5052 {
5053
5054 /* Yes, Client must have sent a DHCP message with improperly terminated option
5055 data (or Client is using a super large DHCP packet). */
5056 return(NX_DHCP_IMPROPERLY_TERMINATED_OPTION);
5057 }
5058
5059 /* Get the next option. */
5060 _nx_dhcp_server_get_data(work_ptr, 1, &value);
5061
5062 /* Move up the buffer pointer to the option length. */
5063 work_ptr++;
5064
5065 /* Get the option length. */
5066 _nx_dhcp_server_get_data(work_ptr, 1, (ULONG *)&size);
5067
5068 /* Move up the buffer pointer to the next option. */
5069 work_ptr++;
5070
5071 /* Validate the size. */
5072 if (work_ptr + size > packet_ptr -> nx_packet_append_ptr)
5073 {
5074 return(NX_DHCP_IMPROPERLY_TERMINATED_OPTION);
5075 }
5076
5077 /* Is this the client ID option? */
5078 if (value != NX_DHCP_SERVER_OPTION_CLIENT_ID)
5079 {
5080
5081 /* Check if there is enough space to store client requested options. */
5082 if (temp_client_rec_ptr -> nx_dhcp_client_option_count < NX_DHCP_CLIENT_OPTIONS_MAX)
5083 {
5084
5085 /* Process as any other option. */
5086 _nx_dhcp_process_option_data(temp_client_rec_ptr, (CHAR *)work_ptr, (UCHAR)value, NX_TRUE, size);
5087 }
5088 }
5089
5090 /* Move up the buffer pointer past the current option data size to the next option. */
5091 work_ptr += size;
5092 }
5093 }
5094
5095 /* Return the location of the client record. */
5096 *dhcp_client_ptr = temp_client_rec_ptr;
5097
5098 return(NX_SUCCESS);
5099 }
5100
5101
5102 /**************************************************************************/
5103 /* */
5104 /* FUNCTION RELEASE */
5105 /* */
5106 /* _nx_dhcp_get_option_data PORTABLE C */
5107 /* 6.1 */
5108 /* AUTHOR */
5109 /* */
5110 /* Yuxin Zhou, Microsoft Corporation */
5111 /* */
5112 /* DESCRIPTION */
5113 /* */
5114 /* This routine extracts data from the specified location and adds the */
5115 /* Client's requested option to the Client record. The caller can ask */
5116 /* for the option data as well to be extracted and stored to client */
5117 /* record. */
5118 /* */
5119 /* INPUT */
5120 /* */
5121 /* dhcp_client_ptr Pointer to DHCP Client */
5122 /* buffer Pointer to data buffer */
5123 /* option Option from Client DHCP packet */
5124 /* size Size of data buffer */
5125 /* get_option_data Indicate if server wants option*/
5126 /* data stored in client record */
5127 /* */
5128 /* OUTPUT */
5129 /* */
5130 /* status Error status extracting data */
5131 /* NX_SUCCESS Successful completion */
5132 /* */
5133 /* CALLS */
5134 /* */
5135 /* _nx_dhcp_server_get_data Extract data from specified */
5136 /* buffer location */
5137 /* memcpy Copy specified area of memory */
5138 /* */
5139 /* CALLED BY */
5140 /* */
5141 /* _nx_dhcp_server_extract_information Extract DHCP data from packet */
5142 /* */
5143 /* RELEASE HISTORY */
5144 /* */
5145 /* DATE NAME DESCRIPTION */
5146 /* */
5147 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5148 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
5149 /* verified memcpy use cases, */
5150 /* fixed the issue of infinite */
5151 /* recursion, */
5152 /* resulting in version 6.1 */
5153 /* */
5154 /**************************************************************************/
_nx_dhcp_process_option_data(NX_DHCP_CLIENT * dhcp_client_ptr,CHAR * buffer,UCHAR option,UINT get_option_data,UINT size)5155 static UINT _nx_dhcp_process_option_data(NX_DHCP_CLIENT *dhcp_client_ptr, CHAR *buffer, UCHAR option, UINT get_option_data, UINT size)
5156 {
5157
5158 UINT status;
5159 ULONG option_value = 0;
5160
5161 /* Do we parse option data for this option? */
5162 if (get_option_data)
5163 {
5164
5165 /* Yes, store to local variable to be applied to the Client record below. */
5166 status = _nx_dhcp_server_get_data((UCHAR *)buffer, size, &option_value);
5167 if (status)
5168 {
5169 return(status);
5170 }
5171 }
5172
5173 switch (option)
5174 {
5175
5176 case 1:
5177 /* Subnet mask */
5178 dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option;
5179 if (get_option_data)
5180 {
5181 dhcp_client_ptr -> nx_dhcp_subnet_mask = option_value;
5182 }
5183 dhcp_client_ptr -> nx_dhcp_client_option_count++;
5184 break;
5185
5186 case 3:
5187 /* Router or gateway */
5188 dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option;
5189 if (get_option_data)
5190 {
5191 dhcp_client_ptr -> nx_dhcp_router_ip_address = option_value;
5192 }
5193 dhcp_client_ptr -> nx_dhcp_client_option_count++;
5194 break;
5195
5196 case 6:
5197 /* Domain name server */
5198 dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option;
5199 if (get_option_data)
5200 {
5201 dhcp_client_ptr -> nx_dhcp_dns_ip_address = option_value;
5202 }
5203 dhcp_client_ptr -> nx_dhcp_client_option_count++;
5204 break;
5205
5206
5207 case 12:
5208 /* Client host name */
5209 dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option;
5210 if (get_option_data)
5211 {
5212
5213 /* Only store as much of the host name as will fit in the host name buffer. */
5214 size = (size <= NX_DHCP_CLIENT_HOSTNAME_MAX) ? size : NX_DHCP_CLIENT_HOSTNAME_MAX;
5215
5216 /* Clear the memory buffer before writing the host name to it. */
5217 memset(&dhcp_client_ptr -> nx_dhcp_client_name[0], 0, NX_DHCP_CLIENT_HOSTNAME_MAX);
5218 memcpy(&dhcp_client_ptr -> nx_dhcp_client_name[0], buffer, size); /* Use case of memcpy is verified. */
5219 }
5220 dhcp_client_ptr -> nx_dhcp_client_option_count++;
5221 break;
5222
5223 case 50:
5224
5225 /* Client's requested IP address */
5226 dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option;
5227 if (get_option_data)
5228 {
5229
5230 dhcp_client_ptr -> nx_dhcp_requested_ip_address = option_value;
5231 }
5232 dhcp_client_ptr -> nx_dhcp_client_option_count++;
5233 break;
5234
5235 case 51:
5236
5237 /* Client's requested IP address lease time */
5238 dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option;
5239 if (get_option_data)
5240 {
5241
5242 dhcp_client_ptr -> nx_dhcp_requested_lease_time = option_value;
5243 }
5244 dhcp_client_ptr -> nx_dhcp_client_option_count++;
5245 break;
5246
5247 case 53:
5248 /* Message type */
5249 dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option;
5250 dhcp_client_ptr -> nx_dhcp_message_type = (UCHAR)option_value;
5251 dhcp_client_ptr -> nx_dhcp_client_option_count++;
5252 break;
5253
5254 case 54:
5255 /* Server ID by which server identifies itself to client(usually server IP address).
5256 The Client includes this option in a REQUEST message to identify which server
5257 it wants to lease an IP address from. */
5258 dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option;
5259 if (get_option_data)
5260 {
5261
5262 dhcp_client_ptr -> nx_dhcp_server_id = option_value;
5263 }
5264 dhcp_client_ptr -> nx_dhcp_client_option_count++;
5265 break;
5266
5267 case 55:
5268
5269 /* Check if there is enough space to store all the client requested options. */
5270 if (dhcp_client_ptr -> nx_dhcp_client_option_count + size > NX_DHCP_CLIENT_OPTIONS_MAX)
5271 {
5272 size = NX_DHCP_CLIENT_OPTIONS_MAX - dhcp_client_ptr -> nx_dhcp_client_option_count;
5273 }
5274
5275 /* Update the client record with that option. */
5276 memcpy(&(dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count]), buffer, size); /* Use case of memcpy is verified. */
5277 dhcp_client_ptr -> nx_dhcp_client_option_count += size;
5278 break;
5279
5280 case 61:
5281
5282 /* Note Client ID is handled separately. */
5283 dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option;
5284 dhcp_client_ptr -> nx_dhcp_client_option_count++;
5285
5286 break;
5287
5288 case 116: /* Auto configuration option */
5289 case 60: /* Vendor class Identifier. */
5290
5291 /* Not supported at this time. */
5292 break;
5293
5294 default:
5295 break;
5296 }
5297
5298 return(NX_SUCCESS);
5299 }
5300
5301
5302 /**************************************************************************/
5303 /* */
5304 /* FUNCTION RELEASE */
5305 /* */
5306 /* _nx_dhcp_add_requested_option PORTABLE C */
5307 /* 6.1 */
5308 /* AUTHOR */
5309 /* */
5310 /* Yuxin Zhou, Microsoft Corporation */
5311 /* */
5312 /* DESCRIPTION */
5313 /* */
5314 /* This routine receives options and which interface the DHCP client is*/
5315 /* on and adds the server information if there is any for that option */
5316 /* into the packet reply buffer. */
5317 /* */
5318 /* INPUT */
5319 /* */
5320 /* dhcp_message Pointer to message buffer */
5321 /* iface_index Index to server interface table*/
5322 /* buffer Pointer to buffer to write to */
5323 /* option Option to add */
5324 /* */
5325 /* OUTPUT */
5326 /* */
5327 /* NX_SUCCESS Successful completion status */
5328 /* status Actual completion status */
5329 /* */
5330 /* CALLS */
5331 /* */
5332 /* _nx_dhcp_add_option Adds the actual option to the */
5333 /* DHCP message buffer */
5334 /* */
5335 /* CALLED BY */
5336 /* */
5337 /* _nx_dhcp_respond_to_dhcp_message Prepare and send out DHCP */
5338 /* response to client */
5339 /* */
5340 /* RELEASE HISTORY */
5341 /* */
5342 /* DATE NAME DESCRIPTION */
5343 /* */
5344 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5345 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5346 /* resulting in version 6.1 */
5347 /* */
5348 /**************************************************************************/
_nx_dhcp_add_requested_option(NX_DHCP_SERVER * dhcp_ptr,UINT iface_index,UCHAR * buffer,UINT option,UINT * index)5349 static UINT _nx_dhcp_add_requested_option(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, UCHAR *buffer, UINT option, UINT *index)
5350 {
5351
5352 UINT status = NX_SUCCESS;
5353
5354 /* The NetX DHCP server provides a limited list of DHCP options for ACK responses. These do NOT
5355 include the server's 'required' options. */
5356 switch (option)
5357 {
5358
5359 case 1: /* Subnet mask */
5360 status = _nx_dhcp_add_option(buffer, option, NX_DHCP_SERVER_OPTION_SUBNET_MASK_SIZE,
5361 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask, index);
5362 break;
5363
5364 case 3: /* Router IP address */
5365
5366
5367 status = _nx_dhcp_add_option(buffer, option, NX_DHCP_SERVER_OPTION_ROUTER_SIZE,
5368 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_router_ip_address, index);
5369 break;
5370
5371 case 6: /* DNS IP address */
5372 status = _nx_dhcp_add_option(buffer, option, NX_DHCP_SERVER_OPTION_ADDRESS_SIZE,
5373 dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_dns_ip_address, index);
5374 break;
5375
5376 /* The NetX DHCP server does not reply to other options at this time. */
5377 default:
5378 break;
5379 }
5380
5381 return(status);
5382 }
5383
5384
5385 /**************************************************************************/
5386 /* */
5387 /* FUNCTION RELEASE */
5388 /* */
5389 /* _nx_dhcp_add_option PORTABLE C */
5390 /* 6.1 */
5391 /* AUTHOR */
5392 /* */
5393 /* Yuxin Zhou, Microsoft Corporation */
5394 /* */
5395 /* DESCRIPTION */
5396 /* */
5397 /* This routine adds a DHCP option data to the DHCP message in the */
5398 /* supplied buffer. Adding the option includes adding the option code,*/
5399 /* length of the data and option data value. */
5400 /* */
5401 /* INPUT */
5402 /* */
5403 /* dhcp_message Pointer to message buffer */
5404 /* option Option to add */
5405 /* value Value of Option to add */
5406 /* */
5407 /* OUTPUT */
5408 /* */
5409 /* status Completion status */
5410 /* */
5411 /* CALLS */
5412 /* */
5413 /* _nx_dhcp_server_store_data Store data value */
5414 /* */
5415 /* CALLED BY */
5416 /* */
5417 /* _nx_dhcp_process Process the DHCP state machine*/
5418 /* */
5419 /* RELEASE HISTORY */
5420 /* */
5421 /* DATE NAME DESCRIPTION */
5422 /* */
5423 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5424 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5425 /* resulting in version 6.1 */
5426 /* */
5427 /**************************************************************************/
_nx_dhcp_add_option(UCHAR * dhcp_message,UINT option,UINT size,ULONG value,UINT * index)5428 static UINT _nx_dhcp_add_option(UCHAR *dhcp_message, UINT option, UINT size, ULONG value, UINT *index)
5429 {
5430
5431
5432 /* Store the option. */
5433 *(dhcp_message + (*index)) = (UCHAR)option;
5434 (*index) ++;
5435
5436 /* Store the option size. */
5437 *(dhcp_message + (*index)) = (UCHAR)size;
5438 (*index) ++;
5439
5440 /* Store the option value. */
5441 _nx_dhcp_server_store_data(dhcp_message + (*index), size, value);
5442 (*index) += size;
5443
5444 /* Return a successful completion. */
5445 return(NX_SUCCESS);
5446 }
5447
5448
5449 /**************************************************************************/
5450 /* */
5451 /* FUNCTION RELEASE */
5452 /* */
5453 /* _nx_dhcp_server_get_data PORTABLE C */
5454 /* 6.1 */
5455 /* AUTHOR */
5456 /* */
5457 /* Yuxin Zhou, Microsoft Corporation */
5458 /* */
5459 /* DESCRIPTION */
5460 /* */
5461 /* This routine gets a data value from a buffer, assuming the data is */
5462 /* stored in standard Network format (big endian). Up to 4 bytes of */
5463 /* data are used, if there are more than 4 bytes, only the lower 4 */
5464 /* bytes are returned. */
5465 /* */
5466 /* INPUT */
5467 /* */
5468 /* data Pointer to buffer data */
5469 /* size Size of data value */
5470 /* value Data value retrieved */
5471 /* */
5472 /* OUTPUT */
5473 /* */
5474 /* NX_SUCCESS Successful completion */
5475 /* NX_DHCP_PARAMETER_ERROR Invalid parameter input */
5476 /* */
5477 /* CALLS */
5478 /* */
5479 /* None */
5480 /* */
5481 /* CALLED BY */
5482 /* */
5483 /* _nx_dhcp_get_response Get response from server */
5484 /* _nx_dhcp_server_extract_information Extract server information */
5485 /* _nx_dhcp_update_address_list Update address list */
5486 /* */
5487 /* RELEASE HISTORY */
5488 /* */
5489 /* DATE NAME DESCRIPTION */
5490 /* */
5491 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5492 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5493 /* resulting in version 6.1 */
5494 /* */
5495 /**************************************************************************/
_nx_dhcp_server_get_data(UCHAR * data,UINT size,ULONG * value)5496 static UINT _nx_dhcp_server_get_data(UCHAR *data, UINT size, ULONG *value)
5497 {
5498
5499
5500 /* Check for invalid buffer parameters. */
5501 if ((size == 0) || (data == 0x0) || (value == 0))
5502 {
5503 return(NX_DHCP_PARAMETER_ERROR);
5504 }
5505
5506 /* Initialize value to zero. */
5507 *value = 0;
5508
5509 /* Store each byte of data from buffer into result. */
5510 while (size > 0)
5511 {
5512
5513 /* Build return value. */
5514 *value = (*value << 8) | *data++;
5515 size--;
5516 }
5517
5518 /* Return value. */
5519 return(NX_SUCCESS);
5520 }
5521
5522
5523 /**************************************************************************/
5524 /* */
5525 /* FUNCTION RELEASE */
5526 /* */
5527 /* _nx_dhcp_server_store_data PORTABLE C */
5528 /* 6.1 */
5529 /* AUTHOR */
5530 /* */
5531 /* Yuxin Zhou, Microsoft Corporation */
5532 /* */
5533 /* DESCRIPTION */
5534 /* */
5535 /* This function stores a data value in a buffer in standard Network */
5536 /* format (big endian) where the destination may be unaligned. Up to */
5537 /* 4 bytes of data are stored, if the size is larger than 4 bytes, the */
5538 /* remaining bytes are set to zero. */
5539 /* */
5540 /* INPUT */
5541 /* */
5542 /* data Pointer to buffer data */
5543 /* size Size of data value */
5544 /* value Value to store */
5545 /* */
5546 /* OUTPUT */
5547 /* */
5548 /* None */
5549 /* */
5550 /* CALLS */
5551 /* */
5552 /* None */
5553 /* */
5554 /* CALLED BY */
5555 /* */
5556 /* _nx_dhcp_send_request Send DHCP request */
5557 /* _nx_dhcp_add_option Add a DHCP option */
5558 /* */
5559 /* RELEASE HISTORY */
5560 /* */
5561 /* DATE NAME DESCRIPTION */
5562 /* */
5563 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5564 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5565 /* resulting in version 6.1 */
5566 /* */
5567 /**************************************************************************/
_nx_dhcp_server_store_data(UCHAR * data,UINT size,ULONG value)5568 static VOID _nx_dhcp_server_store_data(UCHAR *data, UINT size, ULONG value)
5569 {
5570
5571 /* Make sure that data is left justified. */
5572 switch (size)
5573 {
5574
5575 case 1:
5576
5577 value <<= 24;
5578 break;
5579
5580 case 2:
5581
5582 value <<= 16;
5583 break;
5584
5585 case 3:
5586
5587 value <<= 8;
5588 break;
5589
5590 default:
5591 break;
5592 }
5593
5594 /* Store the value. */
5595 while (size-- > 0)
5596 {
5597
5598 *data = (UCHAR)((value >> 24) & 0xff);
5599 data++;
5600 value <<= 8;
5601 }
5602 }
5603
5604 #endif /* NX_DISABLE_IPV4 */
5605