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