netx/addons/dhcp/nx_dhcp.c
2021-07-28 07:24:17 +00:00

10726 lines
557 KiB
C

/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** NetX Component */
/** */
/** Dynamic Host Configuration Protocol (DHCP) Client */
/** */
/**************************************************************************/
/**************************************************************************/
#define NX_DHCP_SOURCE_CODE
/* Force error checking to be disabled in this module */
#ifndef NX_DISABLE_ERROR_CHECKING
#define NX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "nx_api.h"
#include "nx_system.h"
#include "nx_ip.h"
#include "nx_arp.h"
#include "nx_dhcp.h"
/* Define the DHCP Internal Function. */
static VOID _nx_dhcp_thread_entry(ULONG ip_instance);
static UINT _nx_dhcp_extract_information(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UCHAR *dhcp_message, UINT length);
static UINT _nx_dhcp_get_option_value(UCHAR *bootp_message, UINT option, ULONG *value, UINT length);
static UINT _nx_dhcp_add_option_value(UCHAR *bootp_message, UINT option, UINT size, ULONG value, UINT *index);
static UINT _nx_dhcp_add_option_string(UCHAR *bootp_message, UINT option, UINT size, UCHAR *value, UINT *index);
static UINT _nx_dhcp_add_option_parameter_request(NX_DHCP *dhcp_ptr, UCHAR *bootp_message, UINT *index);
static ULONG _nx_dhcp_update_timeout(ULONG timeout);
static ULONG _nx_dhcp_update_renewal_timeout(ULONG timeout);
static UCHAR *_nx_dhcp_search_buffer(UCHAR *option_message, UINT option, UINT length);
static ULONG _nx_dhcp_get_data(UCHAR *data, UINT size);
static VOID _nx_dhcp_store_data(UCHAR *data, UINT size, ULONG value);
static VOID _nx_dhcp_move_string(UCHAR *dest, UCHAR *source, UINT size);
static UINT _nx_dhcp_send_request_internal(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UINT dhcp_message_type);
static UINT _nx_dhcp_client_send_with_zero_source_address(NX_DHCP *dhcp_ptr, UINT iface_index, NX_PACKET *packet_ptr);
static ULONG _nx_dhcp_add_randomize(ULONG timeout);
static VOID _nx_dhcp_udp_receive_notify(NX_UDP_SOCKET *socket_ptr);
static VOID _nx_dhcp_packet_process(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *dhcp_interface, NX_PACKET *packet_ptr);
static VOID _nx_dhcp_timeout_entry(ULONG dhcp);
static VOID _nx_dhcp_timeout_process(NX_DHCP *dhcp_ptr);
static UINT _nx_dhcp_interface_record_find(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_INTERFACE_RECORD **interface_record);
static USHORT _nx_dhcp_client_checksum_compute(NX_PACKET *packet_ptr, ULONG protocol,
UINT data_length, ULONG* src_ip_addr,
ULONG* dest_ip_addr);
#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE
static VOID _nx_dhcp_ip_conflict(NX_IP *ip_ptr, UINT interface_index, ULONG ip_address, ULONG physical_msw, ULONG physical_lsw);
#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */
/* Define the Request string that specifies which options are to be added
to the DHCP Client discover request to the server. Additional options
(found in nx_dhcp.h) may be added by calling nx_dhcp_user_option_request(). */
UCHAR _nx_dhcp_request_parameters[] = { NX_DHCP_OPTION_SUBNET_MASK,
NX_DHCP_OPTION_GATEWAYS,
NX_DHCP_OPTION_DNS_SVR};
#define NX_DHCP_REQUEST_PARAMETER_SIZE sizeof(_nx_dhcp_request_parameters)
static struct NX_DHCP_STRUCT *_nx_dhcp_created_ptr;
/* Bring in externs for caller checking code. */
NX_CALLER_CHECKING_EXTERNS
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_create PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP create function call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* ip_ptr Pointer to IP instance */
/* name_ptr DHCP name pointer */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_create Actual DHCP create function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr)
{
UINT status;
/* Check for invalid input pointers. */
if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (dhcp_ptr == NX_NULL))
{
return(NX_PTR_ERROR);
}
/* Call actual DHCP create service. */
status = _nx_dhcp_create(dhcp_ptr, ip_ptr, name_ptr);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_create PORTABLE C */
/* 6.1.8 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function initializes the DHCP structure and associated IP */
/* instance for DHCP operation. In doing so, it creates a packet */
/* pool for DHCP messages, a UDP socket for communication with the */
/* server, and a DHCP processing thread. */
/* */
/* The primary interface is automatically enabled for DHCP. To run */
/* DHCP on a different interface, use the nx_dhcp_set_interface_index */
/* service. To run DHCP on multiple interfaces, see */
/* nx_dhcp_interface_enable and nx_dhcp_interface_start */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* ip_ptr Pointer to IP instance */
/* name_ptr DHCP name pointer */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* nx_packet_pool_create Create the DHCP packet pool */
/* nx_packet_pool_delete Delete the DHCP packet pool */
/* nx_udp_socket_create Create the DHCP UDP socket */
/* nx_udp_socket_delete Delete the DHCP UDP socket */
/* tx_mutex_create Create DHCP mutex */
/* tx_mutex_delete Delete DHCP mutex */
/* tx_thread_create Create DHCP processing thread */
/* tx_timer_create Create DHCP timer */
/* tx_timer_delete Delete DHCP timer */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 08-02-2021 Yuxin Zhou Modified comment(s), and */
/* improved the code, */
/* resulting in version 6.1.8 */
/* */
/**************************************************************************/
UINT _nx_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr)
{
UINT status;
#ifdef NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK
CHAR *temp_ptr;
UINT label_length = 0;
#endif /* NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK */
#ifdef NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK
/* Set the pointer. */
temp_ptr = name_ptr;
/* The total length of a domain name (host name) is restricted to 255 octets or less. */
if (_nx_utility_string_length_check(temp_ptr, NX_NULL, 255))
{
return (NX_DHCP_INVALID_NAME);
}
/* The labels must follow the rules for ARPANET host names. They must
start with a letter, end with a letter or digit, and have as interior
characters only letters, digits, and hyphen. There are also some
restrictions on the length. Labels must be 63 characters or less.
RFC 1035, Section 2.3.1, Page8. */
while (*temp_ptr)
{
/* Is a dot? */
if (*temp_ptr == '.')
{
/* Current label is end. */
/* Labels must be 63 characters or less, and check the continuous dot '..' for host name. */
if ((label_length == 0) || (label_length > 63))
return (NX_DHCP_INVALID_NAME);
/* End with a letter or digit. Only need to check the Hyphen '-' since
*(temp_ptr - 1) must be Letter, Hyphen or Digits in 'else'. */
if (*(temp_ptr - 1) == '-')
return (NX_DHCP_INVALID_NAME);
/* Continue the next lable. */
label_length = 0;
}
else
{
/* Update the lable length. */
label_length++;
/* Letter. */
if((((*temp_ptr) | 0x20) >= 'a') && (((*temp_ptr) | 0x20) <= 'z'))
{
/* Continue next character. */
temp_ptr++;
continue;
}
/* Start with a letter. */
if (label_length == 1)
return (NX_DHCP_INVALID_NAME);
/* Hyphen or Digits. */
if ((*temp_ptr != '-') &&
((*temp_ptr < '0') || (*temp_ptr > '9')))
return (NX_DHCP_INVALID_NAME);
}
/* Continue next character. */
temp_ptr++;
}
/* Check again if the host name have not the 'dot' terminator. */
if (*(temp_ptr - 1) != '.')
{
/* Labels must be 63 characters or less. */
if (label_length > 63)
return (NX_DHCP_INVALID_NAME);
/* End with a letter or digit. Only need to check the Hyphen '-' since
*(temp_ptr - 1) must be Letter, Hyphen or Digits in 'else'. */
if (*(temp_ptr - 1) == '-')
return (NX_DHCP_INVALID_NAME);
}
#endif /* NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK */
/* Initialize the DHCP control block to zero. */
memset((void *) dhcp_ptr, 0, sizeof(NX_DHCP));
/* Save the IP pointer. */
dhcp_ptr -> nx_dhcp_ip_ptr = ip_ptr;
/* Save the DHCP name. */
dhcp_ptr -> nx_dhcp_name = name_ptr;
/* If the host does not intend to supply their own packet pool, create one here. */
#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL
/* Check the packet payload size, DHCP Client must be prepared to receive a message of up to 576 octets.
RFC 2131, Section 2, Page10. */
if (NX_DHCP_PACKET_PAYLOAD < (NX_PHYSICAL_HEADER + NX_DHCP_MINIMUM_IP_DATAGRAM))
{
/* Invalid payload, return error status. */
return(NX_DHCP_INVALID_PAYLOAD);
}
/* Create the pool and check the status */
status = nx_packet_pool_create(&dhcp_ptr -> nx_dhcp_pool, "NetX DHCP Client", NX_DHCP_PACKET_PAYLOAD,
dhcp_ptr -> nx_dhcp_pool_area, NX_DHCP_PACKET_POOL_SIZE);
/* Determine if it was successful. */
if (status != NX_SUCCESS)
{
/* No, return error status. */
return(status);
}
/* Set an internal packet pool pointer to the newly created packet pool. */
dhcp_ptr -> nx_dhcp_packet_pool_ptr = &dhcp_ptr -> nx_dhcp_pool;
#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION
/* Set the maximum DHCP message size. */
dhcp_ptr -> nx_dhcp_max_dhcp_message_size = NX_DHCP_PACKET_PAYLOAD - NX_PHYSICAL_HEADER;
#endif /* NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION */
#endif /* NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL */
/* Create the Socket and check the status */
status = nx_udp_socket_create(ip_ptr, &(dhcp_ptr -> nx_dhcp_socket), "NetX DHCP Client",
NX_DHCP_TYPE_OF_SERVICE, NX_DHCP_FRAGMENT_OPTION, NX_DHCP_TIME_TO_LIVE, NX_DHCP_QUEUE_DEPTH);
/* Was the socket creation successful? */
if (status != NX_SUCCESS)
{
#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL
/* Delete the packet pool. */
nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr);
#endif
/* No, return error status. */
return(status);
}
/* Set the UDP socket receive callback function. */
status = nx_udp_socket_receive_notify(&(dhcp_ptr -> nx_dhcp_socket), _nx_dhcp_udp_receive_notify);
/* Check status. */
if (status != NX_SUCCESS)
{
#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL
/* Delete the packet pool. */
nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr);
#endif
/* Delete the UDP socket. */
nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
}
/* Create the ThreadX activity timeout timer. This will be used to periodically check to see if
a client connection has gone silent and needs to be terminated. */
status = tx_timer_create(&(dhcp_ptr -> nx_dhcp_timer), "DHCP Client Timer", _nx_dhcp_timeout_entry,
(ULONG)(ALIGN_TYPE)dhcp_ptr, (NX_DHCP_TIME_INTERVAL),
(NX_DHCP_TIME_INTERVAL), TX_NO_ACTIVATE);
/* Determine if the semaphore creation was successful. */
if (status != TX_SUCCESS)
{
/* Delete the UDP socket. */
nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL
/* Delete the packet pool. */
nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr);
#endif
/* No, return error status. */
return(status);
}
/* Create the DHCP mutex. */
status = tx_mutex_create(&(dhcp_ptr -> nx_dhcp_mutex), "NetX DHCP Client", TX_NO_INHERIT);
/* Determine if the semaphore creation was successful. */
if (status != TX_SUCCESS)
{
/* Delete the UDP socket. */
nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL
/* Delete the packet pool. */
nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr);
#endif
/* Delete the timer. */
tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer));
/* No, return error status. */
return(status);
}
/* Create the DHCP processing thread. */
status = tx_thread_create(&(dhcp_ptr -> nx_dhcp_thread), "NetX DHCP Client", _nx_dhcp_thread_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr,
dhcp_ptr -> nx_dhcp_thread_stack, NX_DHCP_THREAD_STACK_SIZE,
NX_DHCP_THREAD_PRIORITY, NX_DHCP_THREAD_PRIORITY, 1, TX_DONT_START);
/* Determine if the thread creation was successful. */
if (status != TX_SUCCESS)
{
/* Delete the mutex. */
tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex));
/* Delete the UDP socket. */
nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL
/* Delete the packet pool. */
nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr);
#endif
/* Delete the timer. */
tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer));
/* No, return error status. */
return(status);
}
/* Create a DHCP event flag group. . */
status = tx_event_flags_create(&(dhcp_ptr -> nx_dhcp_events), (CHAR *)"DHCP Client Events");
/* Check for error. */
if (status != TX_SUCCESS)
{
/* Delete the thread. */
tx_thread_delete(&(dhcp_ptr -> nx_dhcp_thread));
/* Delete the mutex. */
tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex));
/* Delete the timer. */
tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer));
/* Delete the UDP socket. */
nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL
/* Delete the packet pool. */
nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr);
#endif
/* No, return error status. */
return(status);
}
/* Update the dhcp structure ID. */
dhcp_ptr -> nx_dhcp_id = NX_DHCP_ID;
/* Save the DHCP instance. */
_nx_dhcp_created_ptr = dhcp_ptr;
/* Default enable DHCP on the primary interface (0). */
_nx_dhcp_interface_enable(dhcp_ptr, 0);
/* Return a successful status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_clear_broadcast_flag PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP set the clear broadcast */
/* flag in DHCP Client messages service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* clear_flag Broadcast flag status */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_clear_broadcast_flag Actual DHCP Client clear */
/* broadcast flag service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag)
{
UINT status;
/* Check for invalid input pointer. */
if (dhcp_ptr == NX_NULL)
{
return(NX_PTR_ERROR);
}
/* Call actual DHCP clear flag service. */
status = _nx_dhcp_clear_broadcast_flag(dhcp_ptr, clear_flag);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_clear_broadcast_flag PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This service uses the clear_flag input to clear or set the broadcast*/
/* in DHCP Client messages to the DHCP server. By default the broadcast*/
/* flag is set. */
/* */
/* This function is intended for DHCP Clients whose DHCP messages are */
/* routed through a relay agent (router) that will not accept DHCP */
/* messages with broadcast replies requested. */
/* */
/* NX_TRUE broadcast flag is cleared for all messages */
/* NX_FALSE broadcast flag set only if it normally would be */
/* */
/* The server reply will actually be broadcast when relayed by the */
/* router using this strategy. */
/* */
/* If DHCP is enabled on multiple interfaces, this service will set the*/
/* broadcast flag on all interfaces. To set this flag on a specific */
/* interface, use the nx_dhcp_interface_clear_broadcast_flag. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* clear_flag Broadcast flag status */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag)
{
UINT i;
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Loop to set the broadcast flag for all interface record enabled. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if this record is valid. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE)
{
dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_clear_broadcast = clear_flag;
}
}
/* Release the mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return a successful status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_clear_broadcast_flag PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the interface specific clear */
/* broadcast flag service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Network interface index */
/* clear_flag Broadcast flag status */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_clear_broadcast_flag Actual DHCP Client clear */
/* broadcast flag service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag)
{
UINT status;
/* Check for invalid input pointer. */
if (dhcp_ptr == NX_NULL)
{
return(NX_PTR_ERROR);
}
/* Check interface index. */
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return(NX_INVALID_INTERFACE);
}
/* Call actual DHCP clear flag service. */
status = _nx_dhcp_interface_clear_broadcast_flag(dhcp_ptr, iface_index, clear_flag);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interace_clear_broadcast_flag PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This service uses the clear_flag input to determine if the DHCP */
/* Client on the specified network interface should clear the broadcast*/
/* flag in its DHCP messages to the DHCP server (normally it sets the */
/* broadcast flag. */
/* */
/* This is intended for DHCP Clients whose DHCP messages are routed */
/* through arelay agent (router) that will not accept DHCP messages */
/* withbroadcast replies requested. */
/* */
/* NX_TRUE broadcast flag is cleared for all messages */
/* NX_FALSE broadcast flag set only if it normally would be */
/* */
/* The server reply will actually be broadcast when relayed by the */
/* router using this strategy. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Network interface index */
/* clear_flag Broadcast flag status */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Completion status */
/* */
/* CALLS */
/* */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* _nx_dhcp_interface_record_find Find Client record for input */
/* DHCP interface */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag)
{
UINT status;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Set or clear the option to request unicast/clear broadcast flag. */
interface_record -> nx_dhcp_clear_broadcast = clear_flag;
/* Release the mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return a successful status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_packet_pool_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking for the set the DHCP Client */
/* packet pool service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* packet_pool_ptr Pointer to packet pool */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Packet pool successfully set */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_NOT_ENABLED DHCP client not enabled for */
/* user create packet pool */
/* */
/* CALLS */
/* */
/* _nx_dhcp_packet_pool_set */
/* Actual set packet pool service*/
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr)
{
#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL
NX_PARAMETER_NOT_USED(dhcp_ptr);
NX_PARAMETER_NOT_USED(packet_pool_ptr);
/* Client not configured for the user creating the packet pool. Return an error status. */
return NX_NOT_ENABLED;
#else
UINT status;
/* Check for invalid pointer input. */
if ((dhcp_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL))
{
return NX_PTR_ERROR;
}
/* Check the packet payload size, DHCP Client must be prepared to receive a message of up to 576 octets.
RFC2131, Section2, Page10. */
if (packet_pool_ptr -> nx_packet_pool_payload_size < (NX_PHYSICAL_HEADER + NX_DHCP_MINIMUM_IP_DATAGRAM))
{
/* Invalid payload, return error status. */
return(NX_DHCP_INVALID_PAYLOAD);
}
status = _nx_dhcp_packet_pool_set(dhcp_ptr, packet_pool_ptr);
return status;
#endif
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_packet_pool_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the DHCP Client packet pool by passing in a */
/* packet pool pointer to packet pool already create. The */
/* NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL must be set. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* packet_pool_ptr Pointer to packet pool */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful completion status */
/* NX_NOT_ENABLED Setting DHCP Client packet */
/* pool not enabled */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr)
{
/* Determine if the DHCP Client is configured for accepting a packet pool pointer. */
#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL
NX_PARAMETER_NOT_USED(dhcp_ptr);
NX_PARAMETER_NOT_USED(packet_pool_ptr);
/* No, return the error status. */
return NX_NOT_ENABLED;
#else
/* Set the Client packet pool to the supplied packet pool. */
dhcp_ptr -> nx_dhcp_packet_pool_ptr = packet_pool_ptr;
#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION
/* Set the maximum DHCP message size. */
dhcp_ptr -> nx_dhcp_max_dhcp_message_size = packet_pool_ptr -> nx_packet_pool_payload_size - NX_PHYSICAL_HEADER;
#endif /* NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION */
return NX_SUCCESS;
#endif
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_reinitialize PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking for the reinitialize service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_reinitialize(NX_DHCP *dhcp_ptr)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return NX_PTR_ERROR;
}
/* Call the actual reinitialize service. */
status = _nx_dhcp_reinitialize(dhcp_ptr);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_reinitialize PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reinitializes all enabled DHCP interfaces for */
/* restarting the DHCP client protocol. Network parameters in the DHCP*/
/* Client and IP interface(s) are both cleared, and sets the DHCP state*/
/* back to the not started state. */
/* */
/* To reinitialize the DHCP Client on a specific interface when */
/* multiple interfaces are enabled for DHCP, use the */
/* nx_dhcp_interface_reinitialize service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Actual completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_reinitialize Reinitialize DHCP interface */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_reinitialize(NX_DHCP *dhcp_ptr)
{
UINT i;
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER);
/* Loop to reinitalize the record. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if this record is valid. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE)
{
/* Reinitialize the record. */
_nx_dhcp_interface_reinitialize(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index);
}
}
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_reinitialize PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the reinitialize service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Specify interface to init */
/* */
/* OUTPUT */
/* */
/* status Actual completion status */
/* NX_INVALID_INTERFACE Index exceeds max interface */
/* NX_PTR_ERROR Invalid pointer input */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_reinitialize Actual reinitialize service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return NX_PTR_ERROR;
}
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return NX_INVALID_INTERFACE;
}
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call the actual reinitialize service. */
status = _nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_reinitialize PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reinitializes the DHCP instance for restarting the */
/* DHCP client state machine and re-running the DHCP protocol on the */
/* specified interface. The IP address and other network parameters in*/
/* the DHCP Client and in the IP interface are cleared. */
/* */
/* This function also sets the DHCP server IP address to the broadcast */
/* address and sets the DHCP client state back to the INIT state. */
/* */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Specify interface to init */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_record_find Find Client record for input */
/* DHCP interface */
/* nx_ip_interface_address_set Clear IP inteface address of */
/* the input DHCP interface */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* nx_ip_gateway_address_set Clear the gateway address */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
ULONG ip_address;
ULONG network_mask;
ULONG gateway_address;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Check if have IP address. */
if (interface_record -> nx_dhcp_ip_address)
{
/* Get the IP address. */
status = nx_ip_interface_address_get(dhcp_ptr -> nx_dhcp_ip_ptr, iface_index, &ip_address, &network_mask);
/* Check if the IP address is set by DHCP. */
if ((status == NX_SUCCESS) && (ip_address == interface_record -> nx_dhcp_ip_address))
{
/* Clear the IP address. */
nx_ip_interface_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, iface_index, 0, 0);
}
}
/* Check if have gateway address. */
if (interface_record -> nx_dhcp_gateway_address)
{
/* Get the gateway address. */
gateway_address = dhcp_ptr -> nx_dhcp_ip_ptr->nx_ip_gateway_address;
/* Check the gateway address. */
if ((gateway_address != 0) && (gateway_address == interface_record -> nx_dhcp_gateway_address))
{
/* Clear the Gateway/Router IP address. */
nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, 0);
}
}
/* Initialize the client DHCP IP address with the NULL IP address. */
interface_record -> nx_dhcp_ip_address = NX_BOOTP_NO_ADDRESS;
/* Initialize the client DHCP server IP address. */
interface_record -> nx_dhcp_server_ip = NX_BOOTP_NO_ADDRESS;
/* Clear these DHCP Client network values too.*/
interface_record -> nx_dhcp_gateway_address = NX_BOOTP_NO_ADDRESS;
interface_record -> nx_dhcp_network_mask = NX_BOOTP_NO_ADDRESS;
/* Clear the flag to skip the discovery step. The host application must
call the nx_dhcp_request_ip_address to reset the flag and the requested IP address. */
interface_record -> nx_dhcp_skip_discovery = NX_FALSE;
/* Initialize renew and rebind timeout values to zero. */
interface_record -> nx_dhcp_rebind_time = 0;
interface_record -> nx_dhcp_renewal_time = 0;
/* Setup for infinite lease time request. */
interface_record -> nx_dhcp_lease_time = NX_DHCP_INFINITE_LEASE;
/* Reset the seconds field for starting the DHCP request process. */
interface_record -> nx_dhcp_seconds = 0;
/* Reset the timeout and retransmission interval. */
interface_record -> nx_dhcp_timeout = 0;
interface_record -> nx_dhcp_rtr_interval = 0;
/* Set the DHCP state to the initial state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_NOT_STARTED;
/* Release the mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return NX_SUCCESS;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_request_client_ip PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking for the client ip request */
/* service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* client_request_address Client's requested IP address */
/* skip_discover_message Initialize Client state to */
/* BOOT (skip discover message)*/
/* */
/* OUTPUT */
/* */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* status Completion status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_request_address, UINT skip_discover_message)
{
UINT status;
/* Check for an invalid DHCP pointer . */
if (dhcp_ptr == NX_NULL)
{
/* Return an error. */
return(NX_PTR_ERROR);
}
/* Determine that a nonzero IP address is entered. */
if (client_request_address == NX_BOOTP_NO_ADDRESS)
{
return NX_DHCP_INVALID_IP_REQUEST;
}
/* Call actual request client IP service. */
status = _nx_dhcp_request_client_ip(dhcp_ptr, client_request_address, skip_discover_message);
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_request_client_ip PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the requested client IP address in DHCP Client */
/* messages, and enables or disables the skip discovery option */
/* based on the skip_discover_message input. */
/* */
/* If multiple interfaces are enabled for DHCP, this function sets the */
/* requested Client IP on the first valid interface it finds. */
/* */
/* To set the requested Client IP for a specific interface, use the */
/* nx_dhcp_interface_request_ip() service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* client_request_address Client's requested IP address */
/* skip_discover_message To set DHCP Client flag */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_request_client_ip Interface specific request */
/* IP service */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_request_address, UINT skip_discover_message)
{
UINT i;
UINT status;
/* Obtain the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER);
/* Find the DHCP interface record. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check which interface record is valid. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid)
{
/* Set the request IP. */
status = _nx_dhcp_interface_request_client_ip(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index,
client_request_address, skip_discover_message);
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DHCP_NO_INTERFACES_ENABLED);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_request_client_ip PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the request IP service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Index to apply parameter to */
/* client_request_address Client's requested IP address */
/* skip_discover_message To set DHCP Client flag */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_request_address, UINT skip_discover_message)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return NX_PTR_ERROR;
}
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return NX_INVALID_INTERFACE;
}
status = _nx_dhcp_interface_request_client_ip(dhcp_ptr, iface_index, client_request_address, skip_discover_message);
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_request_client_ip PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the requested client IP address in the client */
/* REQUEST message on the input interface. If the skip_discover_message*/
/* flag is set, the DISCOVER message is skipped when the DHCP Client */
/* (re))starts. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Index to apply parameter to */
/* client_request_address Client's requested IP address */
/* skip_discover_message To set DHCP Client flag */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_record_find Find Client record for the */
/* input interface */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_request_address, UINT skip_discover_message)
{
UINT status;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Obtain the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Use input IP address. */
interface_record -> nx_dhcp_ip_address = client_request_address;
/* Set the flag for skipping the discovery state. */
interface_record -> nx_dhcp_skip_discovery = skip_discover_message;
/* Release the mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return success! */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_delete PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP delete function call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_delete Actual DHCP delete function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_delete(NX_DHCP *dhcp_ptr)
{
UINT status;
/* Check for invalid input pointers. */
if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID))
return(NX_PTR_ERROR);
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call actual DHCP delete service. */
status = _nx_dhcp_delete(dhcp_ptr);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_delete PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function disables DHCP on all enabled interfaces, deletes the */
/* DHCP instance and releases all of its resources. All DHCP and IP */
/* interface IP addresses and the IP gateway are cleared on all */
/* valid DHCP interfaces. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* nx_dhcp_interface_disable Disable DHCP on interface */
/* nx_packet_pool_delete Delete the DHCP packet pool */
/* nx_udp_socket_delete Delete the DHCP UDP socket */
/* tx_thread_suspend Suspend DHCP Thread */
/* tx_thread_terminate Terminate DHCP thread */
/* tx_mutex_delete Delete DHCP mutex */
/* tx_event_flags_delete Delete DHCP flag group */
/* tx_timer_deactivate Stop the DHCP timer */
/* tx_timer_delete Delete the DHCP timer */
/* tx_thread_delete Delete DHCP thread */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_delete(NX_DHCP *dhcp_ptr)
{
UINT i;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Disable all the interfaces enabled for DHCP. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if this interface (i) is enabled for DHCP. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid)
{
/* Disable the interface record. */
_nx_dhcp_interface_disable(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index);
}
}
tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread));
/* Terminate the DHCP processing thread. */
tx_thread_terminate(&(dhcp_ptr -> nx_dhcp_thread));
/* Delete the DHCP processing thread. */
tx_thread_delete(&(dhcp_ptr -> nx_dhcp_thread));
/* Delete the DHCP event flags. */
tx_event_flags_delete(&(dhcp_ptr -> nx_dhcp_events));
tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer));
tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer));
/* Unbind the port. */
nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket));
/* Delete the UDP socket. */
nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket));
#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL
/* Delete the packet pool. */
nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr);
#endif
/* Get the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Delete the DHCP mutex. */
tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex));
/* Clear the dhcp structure ID. */
dhcp_ptr -> nx_dhcp_id = 0;
/* Return a successful status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_force_renew PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP force renew function */
/* call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_force_renew Actual DHCP force renew */
/* function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_force_renew(NX_DHCP *dhcp_ptr)
{
UINT status;
/* Check for invalid input pointer. */
if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID))
return(NX_PTR_ERROR);
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call actual DHCP force renew service. */
status = _nx_dhcp_force_renew(dhcp_ptr);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_force_renew PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function forces the DHCP processing thread to renew the lease */
/* on all valid (DHCP enabled) interfaces. To force renew on a specific*/
/* interface if multiple interfaces are enabled for DHCP, use the */
/* nx_dhcp_interface_force_renew service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* nx_dhcp_interface_force_renew Force renew on DHCP interface */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_force_renew(NX_DHCP *dhcp_ptr)
{
UINT i;
/* Obtain the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if this record is valid. */
if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) &&
(dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND))
{
/* Force renew on this interface. */
_nx_dhcp_interface_force_renew(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index);
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return (NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_force_renew PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function forces the DHCP processing thread to renew the lease */
/* on the specified interface. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to force renew on */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* nx_dhcp_interface_force_renew Actual force renew service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return(NX_PTR_ERROR);
}
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return(NX_INVALID_INTERFACE);
}
/* Call the actual reinitialize service. */
status = _nx_dhcp_interface_force_renew(dhcp_ptr, iface_index);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_force_renew PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function allows the DHCP Client to force a renew on a */
/* previously obtained lease on the input interface. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to force renew on */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_record_find Find record for the interface */
/* _nx_dhcp_send_request_internal Send request to DHCP server */
/* _nx_dhcp_update_renewal_timeout Update time left on renew lease*/
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record for this interface. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return status. */
return(status);
}
/* Determine if DHCP is in the Bound state. */
if (interface_record -> nx_dhcp_state >= NX_DHCP_STATE_BOUND)
{
/* Since the Client is initiating RENEW ('force' renew'), set the state to RENEW. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_RENEWING;
/* Send the renew request. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST);
/* Reset the renew time remaining (before transition to the REBIND state) and
the dhcp timeout for retransmission of RENEW request. */
interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_time;
interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time);
/* Record the retransmission interval. */
interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout;
/* Determine if the application has specified a routine for DHCP state change notification. */
if (dhcp_ptr -> nx_dhcp_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state);
}
/* Determine if the application has specified a routine for DHCP interface state change notification. */
if (dhcp_ptr -> nx_dhcp_interface_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state);
}
}
else
{
/* Return a not bound error code. */
status = NX_DHCP_NOT_BOUND;
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return completion status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_decline PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP decline function call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_decline Actual DHCP decline function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_decline(NX_DHCP *dhcp_ptr)
{
UINT status;
/* Check for an invalid input pointer. */
if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID))
return(NX_PTR_ERROR);
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call actual DHCP release service. */
status = _nx_dhcp_decline(dhcp_ptr);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_decline PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function declines the IP address(es) assigned to the DHCP */
/* Client on all valid interfaces. The DHCP Client state is set back */
/* to the INIT state and DHCP is automatically restarted. */
/* */
/* To decline an IP address on a specific interface where multiple */
/* interfaces are enabled for DHCP, use the */
/* nx_dhcp_interface_decline service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_decline Interface specific decline */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_decline(NX_DHCP *dhcp_ptr)
{
UINT i;
/* Obtain the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);\
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if this record is valid. */
if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) &&
(dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND))
{
/* Decline the address. */
_nx_dhcp_interface_decline(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index);
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_decline PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the decline service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to decline IP on */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_decline Actual decline service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return(NX_PTR_ERROR);
}
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return(NX_INVALID_INTERFACE);
}
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call the actual decline service. */
status = _nx_dhcp_interface_decline(dhcp_ptr, iface_index);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_decline PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function declines the IP assigned to the input DHCP Client */
/* interface. The DHCP Client state is set back to the INIT state and */
/* DHCP is automatically restarted. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to decline IP on */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_record_find Find record for the interface */
/* _nx_dhcp_send_request_internal Send DHCP request */
/* _nx_dhcp_interface_reinitialize Reset IP and DHCP Client */
/* network parameters */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
UINT original_state;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr ->nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Check the record state. */
if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DHCP_NOT_BOUND);
}
/* Get the original state. */
original_state = interface_record -> nx_dhcp_state;
/* Send the decline DHCP request. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPDECLINE);
/* Reinitialize DHCP. */
_nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index);
/* Start the DHCP protocol again by setting the state back to INIT. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT;
/* Wait for some time before restarting the configuration process to avoid excessive network traffic in case of looping. RFC2131, Section3.1, Page17. */
interface_record -> nx_dhcp_timeout = NX_DHCP_RESTART_WAIT;
/* Set the retransmission interval. */
interface_record -> nx_dhcp_rtr_interval = 0;
/* Check if the state is changed. */
if (original_state != interface_record -> nx_dhcp_state)
{
/* Determine if the application has specified a routine for DHCP state change notification. */
if (dhcp_ptr -> nx_dhcp_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state);
}
/* Determine if the application has specified a routine for DHCP interface state change notification. */
if (dhcp_ptr -> nx_dhcp_interface_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state);
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return completion status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_release PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP release function call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* */
/* CALLS */
/* */
/* _nx_dhcp_release Actual DHCP release function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_release(NX_DHCP *dhcp_ptr)
{
UINT status;
/* Check for an invalid input pointer. */
if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID))
return(NX_PTR_ERROR);
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call actual DHCP release service. */
status = _nx_dhcp_release(dhcp_ptr);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_release PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function releases the IP previously assigned to this DHCP */
/* instance on all interfaces enabled for DHCP. A subsequent call to */
/* nx_dhcp_start initiates a new request to obtain an IP address. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_release Interface specific send */
/* release request service */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_release(NX_DHCP *dhcp_ptr)
{
UINT i;
/* Obtain the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if this record is valid. */
if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) &&
(dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND))
{
/* Release the address. */
_nx_dhcp_interface_release(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index);
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return. */
return (NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_release PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the release service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to release IP on */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_release Actual release service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return(NX_PTR_ERROR);
}
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return(NX_INVALID_INTERFACE);
}
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call the actual interface release service. */
status = _nx_dhcp_interface_release(dhcp_ptr, iface_index);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_release PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function releases the IP previously assigned to this DHCP */
/* interface. The DHCP state is returned back to the NOT STARTED state.*/
/* A subsequent call to _nx_dhcp_interface_start will initiate a new */
/* request to obtain an IP address. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to release IP on */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_record_find Find record for the interface */
/* _nx_dhcp_send_request_internal Send request to DHCP server */
/* _nx_dhcp_interface_reinitialize Clear IP and DHCP network */
/* parameters to restart DHCP */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT i;
UINT status, original_state;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Determine if DHCP is in the Boot state. */
if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return an error code. */
return(NX_DHCP_NOT_BOUND);
}
/* Get the original state. */
original_state = interface_record -> nx_dhcp_state;
/* Send the release DHCP request. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPRELEASE);
/* Reinitialize DHCP. */
_nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index);
/* Check if the state is changed. */
if (original_state != interface_record -> nx_dhcp_state)
{
/* Determine if the application has specified a routine for DHCP state change notification. */
if (dhcp_ptr -> nx_dhcp_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state);
}
/* Determine if the application has specified a routine for DHCP interface state change notification. */
if (dhcp_ptr -> nx_dhcp_interface_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state);
}
}
/* Check if other interfaces are running DHCP. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check which interface record is valid. */
if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) &&
(dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED))
{
/* Yes, other interfaces have started DHCP. We can assume Netx and ThreadX
resources need to stay activated. */
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_SUCCESS);
}
}
/* Has DHCP stopped on all interfaces? */
if (i == NX_DHCP_CLIENT_MAX_RECORDS)
{
/* Yes, stop DHCP Thread. */
tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread));
/* Deactivate DHCP Timer. */
tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer));
/* Unbind UDP socket. */
nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket));
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return completion status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_start PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP start function call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* */
/* CALLS */
/* */
/* _nx_dhcp_start Actual DHCP start function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_start(NX_DHCP *dhcp_ptr)
{
UINT status;
/* Check for invalid input pointer. */
if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID))
return(NX_PTR_ERROR);
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call actual DHCP start service. */
status = _nx_dhcp_start(dhcp_ptr);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_start PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function starts DHCP on all interfaces that are enabled for */
/* DHCP. If no interfaces have previously been started on DHCP, this */
/* function re/starts the DHCP CLient thread, binds the socket and */
/* re/starts the timer. */
/* */
/* To start DHCP on a specific interface if multiple interfaces are */
/* enabled for DHCP, use the nx_dhcp_interface_start service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_DHCP_NO_INTERFACES_STARTED Unable to start any interfaces*/
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_start Interface specific start DHCP */
/* Client service */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_start(NX_DHCP *dhcp_ptr)
{
UINT status;
UINT interfaces_started = 0;
UINT i;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Check all interfaces to find out which need to start the DHCP protocol. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if this record is valid. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE)
{
/* Start DHCP on this interface. */
status = _nx_dhcp_interface_start(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index);
/* Note, not all interfaces are enabled to run, so
status may not be successful. Skip to the next
interface. */
/* Check status. */
if ((status == NX_SUCCESS) || (status == NX_DHCP_ALREADY_STARTED))
{
interfaces_started++;
}
}
}
/* Check if any interfaces started DHCP. */
if (interfaces_started == 0)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Unable to start any interfaces. */
return NX_DHCP_NO_INTERFACES_STARTED;
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return completion status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_start PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking for the interface specific */
/* DHCP start service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to start DHCP */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_start Actual interface start service*/
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return(NX_PTR_ERROR);
}
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return(NX_INVALID_INTERFACE);
}
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call actual DHCP interface start service. */
status = _nx_dhcp_interface_start(dhcp_ptr, iface_index);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_start PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function 'starts' the specified interface. It finds the matching*/
/* DHCP Client record for that interface and checks that the interface */
/* has been enabled for DHCP (see nx_dhcp_interface_enable). It then */
/* checks if any interfaces are running DHCP. If not it binds the DHCP */
/* socket port, activates the DHCP timer, and resumes the DHCP Client */
/* thread. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to start DHCP */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_record_find Find the Client record for the*/
/* specified interface */
/* nx_udp_socket_bind Bind DHCP socket */
/* nx_udp_socket_unbind Unbind DHCP socket */
/* tx_thread_resume Initiate DHCP processing */
/* tx_timer_activate Activate DHCP timer */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT i;
UINT status;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Check if DHCP is already started. */
if (interface_record -> nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DHCP_ALREADY_STARTED);
}
/* Check if other interface are working. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check which interface record is valid. */
if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) &&
(dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED))
{
/* Yes, other interface have started DHCP. */
break;
}
}
/* Check if any interfaces have started DHCP. */
if (i == NX_DHCP_CLIENT_MAX_RECORDS)
{
/* Bind the UDP socket to the DHCP Client port. */
status = nx_udp_socket_bind(&(dhcp_ptr -> nx_dhcp_socket), NX_DHCP_CLIENT_UDP_PORT, NX_WAIT_FOREVER);
/* Check for error */
if (status != NX_SUCCESS)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Resume the DHCP processing thread. */
status = tx_thread_resume(&(dhcp_ptr -> nx_dhcp_thread));
/* Determine if the resume was successful. */
if ((status != TX_SUCCESS) && (status != TX_SUSPEND_LIFTED))
{
/* Error, unbind the DHCP socket. */
nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket));
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Activate DHCP Timer. */
status = tx_timer_activate(&(dhcp_ptr -> nx_dhcp_timer));
/* Determine if the resume was successful. */
if (status != NX_SUCCESS)
{
/* Error, unbind the DHCP socket. */
nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket));
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
}
/* Start DHCP service for this interface record. */
/* Start the DHCP protocol again by setting the state back to INIT. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT;
/* The client begins in INIT state and forms a DHCPDISCOVER message.
The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup.
RFC2131, Section4.4.1, Page36. */
/* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */
interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE;
interface_record -> nx_dhcp_rtr_interval = 0;
/* Determine if the application has specified a routine for DHCP state change notification. */
if (dhcp_ptr -> nx_dhcp_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state);
}
/* Determine if the application has specified a routine for DHCP interface state change notification. */
if (dhcp_ptr -> nx_dhcp_interface_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state);
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return NX_SUCCESS;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_enable PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking for the interface specific */
/* DHCP enable interface service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to enable DHCP */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_add Actual interface enable service*/
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return(NX_PTR_ERROR);
}
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return(NX_INVALID_INTERFACE);
}
/* Call actual DHCP interface enable service. */
status = _nx_dhcp_interface_enable(dhcp_ptr, iface_index);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_enable PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the specified interface as enabled to run DHCP. */
/* It ensures all DHCP parameters are initialized to zero, and uses the */
/* physical interface MAC address to set the unique Client ID used for */
/* transactions with the DHCP server. */
/* */
/* By default the primary interface is enabled in nx_dhcp_create. An */
/* interface must be enabled before DHCP can be started on it. */
/* Thereafter, it is only necessary to call this function on an interface*/
/* that has been disabled. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to enable DHCP */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful completion status */
/* NX_DHCP_NO_RECORDS_AVAILABLE No more records available to */
/* enable DHCP on an interface */
/* */
/* CALLS */
/* */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT i;
ULONG client_physical_lsw, client_physical_msw;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER);
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if this record is valid. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE)
{
/* Check if the interface is already enabled. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index == iface_index)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DHCP_INTERFACE_ALREADY_ENABLED);
}
}
else
{
/* Yes, we found an available record. */
if (interface_record == NX_NULL)
interface_record = &dhcp_ptr -> nx_dhcp_interface_record[i];
}
}
/* Check if we found an valid DHCP interface record. */
if (interface_record == NX_NULL)
{
/* No, release the mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DHCP_NO_RECORDS_AVAILABLE);
}
/* Set this record as valid. */
interface_record -> nx_dhcp_record_valid = NX_TRUE;
/* Set interface index. */
interface_record -> nx_dhcp_interface_index = iface_index;
/* Initialize the client DHCP IP address with the NULL IP address. */
interface_record -> nx_dhcp_ip_address = NX_BOOTP_NO_ADDRESS;
/* Initialize the client DHCP server IP address. */
interface_record -> nx_dhcp_server_ip = NX_BOOTP_NO_ADDRESS;
/* Initialize renew and rebind timeout values to zero. */
interface_record -> nx_dhcp_rebind_time = 0;
interface_record -> nx_dhcp_renewal_time = 0;
/* Setup for infinite lease time request. */
interface_record -> nx_dhcp_lease_time = NX_DHCP_INFINITE_LEASE;
/* Get the client MAC address from the device interface. */
client_physical_msw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw;
client_physical_lsw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw;
/* Generate a 'unique' client transaction ID from the MAC address for each message to the server. */
interface_record -> nx_dhcp_xid = (ULONG)(client_physical_msw ^ client_physical_lsw ^ (ULONG)NX_RAND());
/* Clear the timeout. */
interface_record -> nx_dhcp_timeout = 0;
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_disable PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the disable service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to disable DHCP */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_disable Actual disable service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return(NX_PTR_ERROR);
}
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return(NX_INVALID_INTERFACE);
}
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call the actual delete service. */
status = _nx_dhcp_interface_disable(dhcp_ptr, iface_index);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_disable PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function disables the input interface to run DHCP. The DHCP */
/* Client need not be in any state or DHCP to be started on this */
/* interface to disable it. */
/* */
/* This function clears the DHCP and IP interface network parameters. */
/* Before DHCP can be restarted on this interface, it must be enabled */
/* by calling nx_dhcp_interface_enable. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to disable DHCP on */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_record_find Find Client record for input */
/* interface */
/* _nx_dhcp_interface_reinitialize Clear DHCP and IP network */
/* parameters */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Obtain the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Reinitalize the DHCP. This clears network values in DHCP and IP interfaces */
_nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index);
/* Set the record as invalid. */
interface_record -> nx_dhcp_record_valid = NX_FALSE;
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_state_change_notify PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP notify function call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* dchp_state_change_notify Application function to call */
/* upon DHCP state change */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_state_change_notify Actual DHCP notify function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state))
{
UINT status;
/* Check for invalid input pointer. */
if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID))
return(NX_PTR_ERROR);
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call actual DHCP notify service. */
status = _nx_dhcp_state_change_notify(dhcp_ptr, dhcp_state_change_notify);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_state_change_notify PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets up an application notification function that is */
/* called whenever a DHCP interface enters a new state. If a NULL */
/* pointer is supplied, the notification is effectively cancelled. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* dchp_state_change_notify Application function to call */
/* upon DHCP state change */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state))
{
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Setup the DHCP notify function. */
dhcp_ptr -> nx_dhcp_state_change_callback = dhcp_state_change_notify;
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return completion status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_state_change_notify PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the state change notify call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* dhcp_state_interface_change_notify Application function to call */
/* upon DHCP state change */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_state_change_notify Actual DHCP notify function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_interface_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state))
{
UINT status;
/* Check for invalid input pointer. */
if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID))
{
return(NX_PTR_ERROR);
}
/* Call actual DHCP notify service. */
status = _nx_dhcp_interface_state_change_notify(dhcp_ptr, dhcp_state_interface_change_notify);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_state_change_notify PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets up an application notification function that is */
/* called whenever DHCP on the input interface enters a new state. If */
/* NULL function pointer is supplied, the notification is cancelled. */
/* The interface on which the DHCP state changed is indicated by the */
/* iface_index input. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* dchp_state_change_notify interface-specific callback */
/* for DHCP state change */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful status */
/* */
/* CALLS */
/* */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_interface_state_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state))
{
/* Obtain the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Setup the DHCP notify function. */
dhcp_ptr -> nx_dhcp_interface_state_change_callback = dhcp_interface_state_change_notify;
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return completion status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_stop PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP stop function call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* */
/* CALLS */
/* */
/* _nx_dhcp_stop Actual DHCP stop function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_stop(NX_DHCP *dhcp_ptr)
{
UINT status;
/* Check for invalid input pointer. */
if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID))
return(NX_PTR_ERROR);
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call actual DHCP stop service. */
status = _nx_dhcp_stop(dhcp_ptr);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_stop PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function halts DHCP processing on all interfaces enabled for */
/* DHCP. The Client state is reset to NOT STARTED, and if no */
/* interfaces are currently running DHCP, this function suspends the */
/* DHCP Client thread, and unbinds the DHCP socket port. */
/* */
/* To stop DHCP on a specific interface when multiple interfaces are */
/* enabled for DHCP, use the nx_dhcp_interface_stop service. */
/* */
/* To restart DHCP Client on a stopped interface, the interface must */
/* be reinitialized using either nx_dhcp_reinitialize() to reinitialize*/
/* all enabled DHCP interfaces, or nx_dhcp_interface_reinitialize() for*/
/* a specific interface. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_stop Interface specific DHCP stop */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_stop(NX_DHCP *dhcp_ptr)
{
UINT i;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Check all interfaces to find out which need to stop the DHCP protocol. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if this record is valid. */
if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) &&
(dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED))
{
/* Stop DHCP. */
_nx_dhcp_interface_stop(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index);
}
}
/* Stop DHCP Thread. */
tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread));
/* Deactivate DHCP Timer. */
tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer));
/* Ubind UDP socket. */
nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket));
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_stop PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking for the interface specific */
/* DHCP stop service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to stop DHCP */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_stop Actual interface stop service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return NX_PTR_ERROR;
}
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return NX_INVALID_INTERFACE;
}
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
status = _nx_dhcp_interface_stop(dhcp_ptr, iface_index);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_stop PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function stops DHCP processing on the specified interface. It */
/* sets the DHCP state to the unstarted status. If any state changes */
/* occurred it calls the record state change callback. */
/* */
/* If DHCP is not started on any of the DHCP Client interfaces, this */
/* function will suspend the thread, unbind the socket and stop the */
/* timer. */
/* */
/* Note: before DHCP Client can be restarted on the interface, the */
/* DHCP Client must be reinitialized by calling */
/* nx_dhcp_interface_reinitialize(). */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to stop DHCP on */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_record_find Find record assigned to the */
/* input interface */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT i;
UINT status;
UINT original_state;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Obtain the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Not found. Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Get the original state. */
original_state = interface_record -> nx_dhcp_state;
/* Determine if DHCP is started. */
if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_NOT_STARTED)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* DHCP is not started so it can't be stopped. */
return(NX_DHCP_NOT_STARTED);
}
/* Set the state to NX_DHCP_STATE_NOT_STARTED. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_NOT_STARTED;
/* Check if the state is changed. */
if (original_state != interface_record -> nx_dhcp_state)
{
/* Determine if the application has specified a routine for DHCP state change notification. */
if (dhcp_ptr -> nx_dhcp_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state);
}
/* Determine if the application has specified a routine for DHCP interface state change notification. */
if (dhcp_ptr -> nx_dhcp_interface_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record->nx_dhcp_state);
}
}
/* Check if other interfaces are running DHCP. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check which interface record is valid. */
if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) &&
(dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED))
{
/* Yes, other interfaces have started DHCP. We can assume Netx and ThreadX
resources need to stay activated. */
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_SUCCESS);
}
}
/* Has DHCP stopped on all interfaces? */
if (i == NX_DHCP_CLIENT_MAX_RECORDS)
{
/* Yes, stop DHCP Thread. */
tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread));
/* Deactivate DHCP Timer. */
tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer));
/* Unbind UDP socket. */
nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket));
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr->nx_dhcp_mutex));
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_user_option_retrieve PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP user option function */
/* call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* option_request Option request */
/* destination_ptr Pointer to return buffer */
/* destination_size Size of return buffer (and */
/* modified to reflect how */
/* much information is in the */
/* response) */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* */
/* CALLS */
/* */
/* _nx_dhcp_user_option_request Actual DHCP user option */
/* function call */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT option_request, UCHAR *destination_ptr, UINT *destination_size)
{
UINT status;
/* Check for invalid input pointer. */
if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID) ||
(destination_ptr == NX_NULL) || (destination_size == NX_NULL))
return(NX_PTR_ERROR);
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call actual DHCP user option request service. */
status = _nx_dhcp_user_option_retrieve(dhcp_ptr, option_request, destination_ptr, destination_size);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_user_option_retrieve PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function searches the DHCP options buffer to obtain the */
/* specified option. If successful, the option is placed in the */
/* supplied destination string. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* option_request Option request */
/* destination_ptr Pointer to return buffer */
/* destination_size Size of return buffer (and */
/* modified to reflect how */
/* much information is in the */
/* response) */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_DHCP_NO_INTERFACES_ENABLED No DHCP interfaces enabled */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_user_option_retrieve */
/* Search DHCP interface options */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT option_request, UCHAR *destination_ptr, UINT *destination_size)
{
UINT i;
UINT status;
/* Obtain the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER);
/* Find the DHCP interface record. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check which interface record is valid. */
if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) &&
(dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND))
{
/* Retrieve the user option. */
status = _nx_dhcp_interface_user_option_retrieve(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index,
option_request, destination_ptr, destination_size);
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DHCP_NO_INTERFACES_ENABLED);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_user_option_request PORTABLE C */
/* 6.1.8 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP user option function */
/* call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* option_code Option code */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* */
/* CALLS */
/* */
/* _nx_dhcp_user_option_request Actual DHCP user option */
/* request function call */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 08-02-2021 Yuxin Zhou Initial Version 6.1.8 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_user_option_request(NX_DHCP *dhcp_ptr, UINT option_code)
{
UINT status;
/* Check for invalid input pointer. */
if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID))
return(NX_PTR_ERROR);
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call actual DHCP interface user option request service. */
status = _nx_dhcp_user_option_request(dhcp_ptr, option_code);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_user_option_request PORTABLE C */
/* 6.1.8 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function requests the additional user option. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* option_code Option code */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 08-02-2021 Yuxin Zhou Initial Version 6.1.8 */
/* */
/**************************************************************************/
UINT _nx_dhcp_user_option_request(NX_DHCP *dhcp_ptr, UINT option_code)
{
UINT i;
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Check if the default option array already has it. */
for (i = 0; i < NX_DHCP_REQUEST_PARAMETER_SIZE; i++)
{
if (_nx_dhcp_request_parameters[i] == option_code)
{
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DUPLICATED_ENTRY);
}
}
/* Check if the user option array already has it. */
for (i = 0; i < dhcp_ptr -> nx_dhcp_user_request_parameter_size; i++)
{
if (dhcp_ptr -> nx_dhcp_user_request_parameter[i] == option_code)
{
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DUPLICATED_ENTRY);
}
}
/* Check if there is space to add option. */
if (dhcp_ptr -> nx_dhcp_user_request_parameter_size >= NX_DHCP_CLIENT_MAX_USER_REQUEST_PARAMETER)
{
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_NO_MORE_ENTRIES);
}
/* Add the option. */
dhcp_ptr -> nx_dhcp_user_request_parameter[dhcp_ptr -> nx_dhcp_user_request_parameter_size++] = (UCHAR)option_code;
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return success. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_user_option_retrieve PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the DHCP user option function */
/* call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface index */
/* option_request Option request */
/* destination_ptr Pointer to return buffer */
/* destination_size Size of return buffer (and */
/* modified to reflect how */
/* much information is in the */
/* response) */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_user_option_request Actual DHCP user option */
/* function call */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size)
{
UINT status;
/* Check for invalid input pointer. */
if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID) ||
(destination_ptr == NX_NULL) || (destination_size == NX_NULL))
return(NX_PTR_ERROR);
/* Check interface index. */
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return(NX_INVALID_INTERFACE);
}
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call actual DHCP interface user option request service. */
status = _nx_dhcp_interface_user_option_retrieve(dhcp_ptr, iface_index, option_request, destination_ptr, destination_size);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_user_option_retrieve PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function searches the DHCP options buffer to obtain the */
/* specified option. If successful, the option is placed in the */
/* supplied destination string. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface index */
/* option_request Option request */
/* destination_ptr Pointer to return buffer */
/* destination_size Size of return buffer (and */
/* modified to reflect how */
/* much information is in the */
/* response) */
/* memcpy Copy specified area of memory */
/* */
/* OUTPUT */
/* */
/* destination_size Size of returned option */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_search_buffer Search the buffer */
/* _nx_dhcp_interface_record_find Find record of input interface*/
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), improved */
/* buffer length verification, */
/* verified memcpy use cases, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size)
{
UCHAR *buffer_ptr;
UINT size;
UINT status;
UINT i;
ULONG *long_ptr;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Check state. */
if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return an error. */
return(NX_DHCP_NOT_BOUND);
}
/* Setup a pointer to the previous buffer. */
buffer_ptr = _nx_dhcp_search_buffer(interface_record -> nx_dhcp_options_buffer,
option_request, interface_record -> nx_dhcp_options_size);
/* Determine if the option was found. */
if (!buffer_ptr)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return an error. */
return(NX_DHCP_PARSE_ERROR);
}
/* Calculate the size of the option. */
size = (UINT) *buffer_ptr;
/* Determine if the destination is large enough. */
if (size > *destination_size)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Server did not respond. */
return(NX_DHCP_DEST_TO_SMALL);
}
/* Skip the option size field. */
buffer_ptr++;
/* Check to see which option data is requested: */
switch (option_request)
{
case NX_DHCP_OPTION_SUBNET_MASK:
case NX_DHCP_OPTION_TIME_OFFSET:
case NX_DHCP_OPTION_GATEWAYS:
case NX_DHCP_OPTION_TIMESVR:
case NX_DHCP_OPTION_DNS_SVR:
case NX_DHCP_OPTION_NTP_SVR:
case NX_DHCP_OPTION_DHCP_LEASE:
case NX_DHCP_OPTION_DHCP_SERVER:
case NX_DHCP_OPTION_RENEWAL:
case NX_DHCP_OPTION_REBIND:
{
/* The length of these options must always be a multiple of 4 octets. */
/* Store the value as host byte order. */
long_ptr = (ULONG *) destination_ptr;
/* Loop to set the long value. */
for (i = 0; i + 4 <= size;)
{
/* Set the long value. */
*long_ptr = _nx_dhcp_get_data(buffer_ptr + i, 4);
/* Update the pointer. */
long_ptr ++;
i += 4;
}
break;
}
default:
{
/* Directly copy the data into destination buffer. */
memcpy(destination_ptr, buffer_ptr, size); /* Use case of memcpy is verified. */
break;
}
}
/* Return the actual option size. */
*destination_size = size;
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return success. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_user_option_convert PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the option convert service.*/
/* */
/* INPUT */
/* */
/* source_ptr Source of string area */
/* */
/* OUTPUT */
/* */
/* value Pointer to conversion value */
/* NULL Invalid pointer input */
/* */
/* CALLS */
/* */
/* _nx_dhcp_user_option_convert Actual option convert service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
ULONG _nxe_dhcp_user_option_convert(UCHAR *source_ptr)
{
ULONG temp;
/* Check for invalid input. */
if (source_ptr == NX_NULL)
{
return NX_NULL;
}
/* Pickup the ULONG. */
temp = _nx_dhcp_user_option_convert(source_ptr);
/* Return the ULONG. */
return(temp);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_user_option_convert PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function converts the four bytes pointed to by the input */
/* string pointer to an ULONG and returns the value. */
/* */
/* INPUT */
/* */
/* source_ptr Source of string area */
/* */
/* OUTPUT */
/* */
/* value Pointer to conversion value */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
ULONG _nx_dhcp_user_option_convert(UCHAR *source_ptr)
{
ULONG temp;
/* Pickup the ULONG. */
temp = (((ULONG) *(source_ptr)) << 24) |
(((ULONG) *(source_ptr+1)) << 16) |
(((ULONG) *(source_ptr+2)) << 8) |
((ULONG) *(source_ptr+3));
/* Return the ULONG. */
return(temp);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_user_option_add_callback_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the user option add */
/* callback set service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* dhcp_user_option_add Pointer to application's */
/* option add function */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_user_option_add_callback_set Actual user option callback */
/* set service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type,
UCHAR *user_option_ptr, UINT *user_option_length))
{
UINT status;
/* Check for invalid input. */
if ((dhcp_ptr == NX_NULL) || (dhcp_user_option_add == NX_NULL))
{
return(NX_PTR_ERROR);
}
/* Call actual DHCP user option callback set service. */
status = _nx_dhcp_user_option_add_callback_set(dhcp_ptr, dhcp_user_option_add);
/* Return status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_user_option_add_callback_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets the user option add callback. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* dhcp_user_option_add Pointer to application's */
/* option add function */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type,
UCHAR *user_option_ptr, UINT *user_option_length))
{
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Set the callback. */
dhcp_ptr -> nx_dhcp_user_option_add = dhcp_user_option_add;
/* Release the mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return a successful status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_udp_receive_notify PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is called when the IP thread task detects a UDP packet*/
/* has been received on this socket. It allows the DHCP Client to make */
/* a non blocking nx_udp_socket_receive call. */
/* */
/* INPUT */
/* */
/* socket_ptr Pointer to DHCP socket */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* tx_event_flags_set Set event packet is received */
/* */
/* CALLED BY */
/* */
/* IP thread task */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _nx_dhcp_udp_receive_notify(NX_UDP_SOCKET *socket_ptr)
{
NX_PARAMETER_NOT_USED(socket_ptr);
/* Set the data received event flag. */
tx_event_flags_set(&(_nx_dhcp_created_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_RECEIVE_EVENT, TX_OR);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_timeout_entry PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is called when the DHCP Client timer expires. It */
/* loops through all valid interfaces that have started DHCP, and */
/* updates their DHCP timeout. If an interface timeout has expired, it*/
/* processes that interface depending on which DHCP state it is in. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* tx_event_flags_set Set an event that timer expired*/
/* */
/* CALLED BY */
/* */
/* ThreadX timer */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _nx_dhcp_timeout_entry(ULONG dhcp)
{
NX_DHCP *dhcp_ptr;
/* Setup DHCP pointer. */
dhcp_ptr = (NX_DHCP *)dhcp;
/* Set the data event flag. */
tx_event_flags_set(&(dhcp_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_TIMER_EVENT, TX_OR);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_thread_entry PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is the processing thread for the DHCP Client. */
/* Its processing consists of executing a while-forever loop that */
/* checks for events (e.g. packet receive, timer expiration). For */
/* received packets, some initial packet validation is done before */
/* calling _nx_dhcp_packet_process. */
/* */
/* INPUT */
/* */
/* dhcp_instance Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* tx_event_flags_get Check for events */
/* _nx_udp_socket_receive Retrieve packet from socket */
/* _nx_dhcp_interface_record_find Find record of this interface */
/* tx_mutex_get Get the DHCP mutex */
/* tx_mutex_put Release the DHCP mutex */
/* _nx_dhcp_packet_process Process received packet */
/* _nx_dhcp_timout_entry Process timer expiration */
/* */
/* CALLED BY */
/* */
/* ThreadX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static VOID _nx_dhcp_thread_entry(ULONG dhcp_instance)
{
NX_DHCP *dhcp_ptr;
NX_PACKET *packet_ptr;
ULONG events;
UINT status;
UINT iface_index;
UINT source_port;
ULONG source_ip_address;
UINT protocol;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Setup the DHCP pointer. */
dhcp_ptr = (NX_DHCP *) dhcp_instance;
/* Obtain the DHCP mutex before processing an. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Enter the DHCP Client task loop. */
do
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Wait for a DHCP client activity. */
tx_event_flags_get(&(dhcp_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_ALL_EVENTS,
TX_OR_CLEAR, &events, TX_WAIT_FOREVER);
/* Obtain the DHCP mutex before processing an. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Check for DHCP data received event. */
if (events & NX_DHCP_CLIENT_RECEIVE_EVENT)
{
/* Loop to receive DHCP message. */
while(1)
{
/* Check for an incoming DHCP packet with non blocking option. */
status = _nx_udp_socket_receive(&dhcp_ptr -> nx_dhcp_socket, &packet_ptr, NX_NO_WAIT);
/* Check for packet receive errors. */
if (status != NX_SUCCESS)
{
break;
}
/* Find the source IP address, port, interface this packet is on. */
status = nx_udp_packet_info_extract(packet_ptr, &source_ip_address, &protocol, &source_port, &iface_index);
/* Check status. */
if (status != NX_SUCCESS)
{
nx_packet_release(packet_ptr);
continue;
}
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status != NX_SUCCESS)
{
/* Release the original packet . */
nx_packet_release(packet_ptr);
continue;
}
/* Process DHCP packet. */
_nx_dhcp_packet_process(dhcp_ptr, interface_record, packet_ptr);
}
}
/* Timer event. */
if (events & NX_DHCP_CLIENT_TIMER_EVENT)
{
_nx_dhcp_timeout_process(dhcp_ptr);
}
#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE
/* IP address conflict event. */
if (events & NX_DHCP_CLIENT_CONFLICT_EVENT)
{
/* Loop to check the interface. */
for (iface_index = 0; iface_index < NX_MAX_PHYSICAL_INTERFACES; iface_index++)
{
/* Check the flag. */
if (dhcp_ptr -> nx_dhcp_interface_conflict_flag == 0)
{
break;
}
/* Check if IP address conflict for this interface. */
if (dhcp_ptr -> nx_dhcp_interface_conflict_flag & ((UINT)(1 << iface_index)))
{
/* Handle notice of address conflict event. Let the server know we
did not get assigned a unique IP address. */
_nx_dhcp_interface_decline(dhcp_ptr, iface_index);
/* Clear the flag. */
dhcp_ptr -> nx_dhcp_interface_conflict_flag &= (UINT)(~(1 << iface_index));
}
}
}
#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */
} while (1);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_packet_process PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is called when the DHCP Client thread is notified of a*/
/* receive event. If verifies the packet is intended for this host, */
/* and checks the transaction ID from the Server to match its ID, */
/* processing the packet based on DHCP state. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* interface_record Pointer to DHCP interface */
/* packet_ptr Pointer to received packet */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_dhcp_find_matching_record Find Client record matching */
/* the packet interface */
/* nx_packet_allocate Allocate new packet from DHCP */
/* Client packet pool */
/* nx_packet_release Release packet back to DHCP */
/* Client packet pool */
/* nx_packet_data_extract_offset Copy data to new packet buffer*/
/* _nx_dhcp_get_option_value Get data for input option */
/* _nx_dhcp_extract_information Extract basic info from packet*/
/* _nx_dhcp_send_request_internal Send DHCP message */
/* nx_ip_interface_address_set Set IP interface address */
/* nx_ip_gateway_address_set Set IP gateway address */
/* _nx_dhcp_interface_reinitialize Clear DHCP interface data */
/* for restarting DHCP */
/* */
/* CALLED BY */
/* */
/* nx_dhcp_thread_entry DHCP Client thread entry fcn */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _nx_dhcp_packet_process(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, NX_PACKET *packet_ptr)
{
UINT status;
NX_PACKET *new_packet_ptr;
ULONG dhcp_type;
UCHAR *work_ptr;
ULONG bytes_copied;
UINT offset;
NX_IP *ip_ptr;
UINT iface_index;
ULONG packet_client_mac_msw, packet_client_mac_lsw;
ULONG dhcp_client_mac_msw, dhcp_client_mac_lsw;
UINT original_state;
UCHAR *buffer;
#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE
ULONG probing_delay;
#endif
/* Set the IP pointer and interface index. */
ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr;
iface_index = interface_record -> nx_dhcp_interface_index;
/* Check for valid packet length. */
if (packet_ptr -> nx_packet_length <= NX_BOOTP_OFFSET_OPTIONS)
{
/* Release the packet. */
nx_packet_release(packet_ptr);
/* Return. */
return;
}
/* Copy the received packet (datagram) over to a packet from the DHCP Client pool and release
the packet back to receive packet pool as soon as possible. */
status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &new_packet_ptr, NX_UDP_PACKET, NX_NO_WAIT);
/* Check status. */
if (status != NX_SUCCESS)
{
/* Release the original packet. */
nx_packet_release(packet_ptr);
/* Error allocating packet, return error status. */
return;
}
/* Verify the incoming packet does not exceed our DHCP Client packet payload. */
if ((ULONG)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < ((packet_ptr) -> nx_packet_length))
{
/* Release the newly allocated packet . */
nx_packet_release(new_packet_ptr);
/* Release the original packet. */
nx_packet_release(packet_ptr);
return;
}
/* Initialize the offset to the beginning of the packet buffer. */
offset = 0;
status = nx_packet_data_extract_offset(packet_ptr, offset, (VOID *)new_packet_ptr -> nx_packet_prepend_ptr, (packet_ptr) -> nx_packet_length, &bytes_copied);
/* Check status. */
if ((status != NX_SUCCESS) || (bytes_copied == 0))
{
/* Release the allocated packet we'll never send. */
nx_packet_release(new_packet_ptr);
/* Release the original packet. */
nx_packet_release(packet_ptr);
/* Error extracting packet buffer, return error status. */
return;
}
/* Update the new packet with the bytes copied. For chained packets, this will reflect the total
'datagram' length. */
new_packet_ptr -> nx_packet_length = bytes_copied;
/* Now we can release the original packet. */
nx_packet_release(packet_ptr);
/* Set the interface index and MAC address. */
dhcp_client_mac_msw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw;
dhcp_client_mac_lsw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw;
/* Set work_ptr. */
work_ptr = new_packet_ptr -> nx_packet_prepend_ptr + NX_BOOTP_OFFSET_CLIENT_HW;
/* Pickup the target MAC address in the DHCP message. */
packet_client_mac_msw = (((ULONG)work_ptr[0]) << 8) | ((ULONG)work_ptr[1]);
packet_client_mac_lsw = (((ULONG)work_ptr[2]) << 24) |
(((ULONG)work_ptr[3]) << 16) |
(((ULONG)work_ptr[4]) << 8) |
((ULONG)work_ptr[5]);
/* Determine if the MAC address matches ours. */
if ((packet_client_mac_msw != dhcp_client_mac_msw) || (packet_client_mac_lsw != dhcp_client_mac_lsw))
{
/* Release the allocated packet. */
nx_packet_release(new_packet_ptr);
return;
}
/* Check if XIDs match. */
if (_nx_dhcp_get_data(new_packet_ptr -> nx_packet_prepend_ptr + NX_BOOTP_OFFSET_XID, 4) != interface_record -> nx_dhcp_xid)
{
/* Release the original packet . */
nx_packet_release(new_packet_ptr);
/* Error with XID data, return error status. */
return;
}
/* Save the original state for the state change callback; after this point we will likely change it. */
original_state = interface_record -> nx_dhcp_state;
/* The action depends on the current state of the dhcp client. */
switch (interface_record -> nx_dhcp_state)
{
case NX_DHCP_STATE_SELECTING:
{
/* Set up a buffer pointer. */
buffer = new_packet_ptr -> nx_packet_prepend_ptr;
/* Get what type of DHCP message it is. */
status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr -> nx_packet_length);
/* Determine if it is an Offer. */
if ((status == NX_SUCCESS) && (dhcp_type == NX_DHCP_TYPE_DHCPOFFER))
{
/* Yes, a valid Offer is received! */
/* Increment the number of offers received. */
interface_record -> nx_dhcp_offers_received++;
/* Update the DHCP Client interface parameters (IP address, server IP, lease, renewal and rebind times */
if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length))
break;
/* Send the DHCP Request to accept the offer. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST);
/* Reset the initial timeout to NX_DHCP_MIN_RETRANS_TIMEOUT seconds */
interface_record -> nx_dhcp_rtr_interval = NX_DHCP_MIN_RETRANS_TIMEOUT;
interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_rtr_interval;
/* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */
interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout);
/* Check if the timeout is zero. */
if (interface_record -> nx_dhcp_timeout == 0)
interface_record -> nx_dhcp_timeout = 1;
/* Update the state to Requesting state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_REQUESTING;
}
/* Let the timeout processing handle retransmissions. We're done here */
break;
}
case NX_DHCP_STATE_REQUESTING:
{
#ifdef NX_DHCP_ENABLE_BOOTP
/* Initialize the value of dhcp type since we do not care for BOOTP. */
dhcp_type = NX_DHCP_TYPE_DHCPACK;
/* Also initialize status to success since we won't make the get option call. */
status = NX_SUCCESS;
#endif
/* Setup buffer pointer. */
buffer = new_packet_ptr -> nx_packet_prepend_ptr;
#ifndef NX_DHCP_ENABLE_BOOTP
/* There is a valid DHCP response, see if it is an ACK. */
status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr ->nx_packet_length);
#endif
/* Proceed to processing the server response? */
if (status == NX_SUCCESS)
{
/* Yes, check and see if it is an ACK back to our previous request. */
if (dhcp_type == NX_DHCP_TYPE_DHCPACK)
{
/* Increment the number of ACKs received. */
interface_record -> nx_dhcp_acks_received++;
/* Either we got an ACK or we are using BOOTP. */
/* Update the parameters (IP address, server IP, lease, renewal and rebind times */
if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length))
break;
/* If the host is configured to send an ARP probe to verify Client address is
not in use, do so now. */
#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE
/* Change to the Address Probing state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_ADDRESS_PROBING;
/* Initalize the time for probing. */
probing_delay = (ULONG)NX_RAND() % (NX_DHCP_ARP_PROBE_WAIT);
/* Check the probing_delay for timer interval. */
if (probing_delay)
interface_record -> nx_dhcp_timeout = probing_delay;
else
interface_record -> nx_dhcp_timeout = 1;
/* Set the probing count. */
interface_record -> nx_dhcp_probe_count = NX_DHCP_ARP_PROBE_NUM;
/* Setup the handler to indicate the we want collision notification. */
ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_conflict_notify_handler = _nx_dhcp_ip_conflict;
#else /* NX_DHCP_CLIENT_SEND_ARP_PROBE not defined: */
nx_ip_interface_address_set(ip_ptr, iface_index,
interface_record -> nx_dhcp_ip_address,
interface_record -> nx_dhcp_network_mask);
/* Check if the gateway address is valid. */
if (interface_record -> nx_dhcp_gateway_address)
{
/* Set the gateway address. */
nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address);
}
/* No ARP probe performed. OK to change to the Bound state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND;
#ifdef NX_DHCP_ENABLE_BOOTP
/* BOOTP does not use timeouts. For the life of this DHCP Client application, keep the same IP address. */
interface_record -> nx_dhcp_timeout = NX_WAIT_FOREVER;
#else
/* Set the renewal time received from the server. */
interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time;
#endif /* NX_DHCP_ENABLE_BOOTP */
#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE*/
break;
}
else if (dhcp_type == NX_DHCP_TYPE_DHCPNACK)
{
/* Increment the number of NACKs received. */
interface_record -> nx_dhcp_nacks_received++;
/* Reinitialize DHCP. */
_nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index);
/* Restart DHCP service for this interface record. */
/* Start the DHCP protocol again by setting the state back to INIT. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT;
/* The client begins in INIT state and forms a DHCPDISCOVER message.
The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup.
RFC2131, Section4.4.1, Page36. */
/* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */
interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE;
interface_record -> nx_dhcp_rtr_interval = 0;
/* Check if the timeout is less than 1 second. */
if (interface_record -> nx_dhcp_timeout < NX_IP_PERIODIC_RATE)
interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE;
}
}
break;
}
case NX_DHCP_STATE_BOUND:
{
/* Silently discard all received packets in the BOUND state, RFC2131, Section 4.4 Figure 5 */
break;
}
case NX_DHCP_STATE_RENEWING:
{
/* Setup the buffer pointer. */
buffer = new_packet_ptr -> nx_packet_prepend_ptr;
/* Check the server response if it accepts are renewal. */
status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr ->nx_packet_length);
/* Was the option retrieved? */
if (status == NX_SUCCESS)
{
/* Yes, Check for an ACK. */
if (dhcp_type == NX_DHCP_TYPE_DHCPACK)
{
/* Increment the number of ACKs received. */
interface_record -> nx_dhcp_acks_received++;
/* Update the parameters (IP address, server IP, lease, renewal and rebind times */
if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length))
break;
/* Set the IP address and gateway address from the value extracted from the Server's DHCP response. */
nx_ip_interface_address_set(ip_ptr, iface_index,
interface_record -> nx_dhcp_ip_address,
interface_record -> nx_dhcp_network_mask);
/* Check if the gateway address is valid. */
if (interface_record -> nx_dhcp_gateway_address)
{
/* Set the gateway address. */
nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address);
}
/* Lease has been renewed, set the countdown timer back to the renewal time and go back
to the Bound state*/
interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time;
/* Change the state back to bound. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND;
}
else if (dhcp_type == NX_DHCP_TYPE_DHCPNACK)
{
/* Increment the number of NACKs received. */
interface_record -> nx_dhcp_nacks_received++;
/* Reinitialize DHCP. */
_nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index);
/* Restart DHCP service for this interface record. */
/* Start the DHCP protocol again by setting the state back to INIT. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT;
/* The client begins in INIT state and forms a DHCPDISCOVER message.
The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup.
RFC2131, Section4.4.1, Page36. */
/* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */
interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE;
interface_record -> nx_dhcp_rtr_interval = 0;
}
}
break;
}
case NX_DHCP_STATE_REBINDING:
{
/* Setup buffer pointer. */
buffer = new_packet_ptr -> nx_packet_prepend_ptr;
/* There is a valid DHCP response, pickup the type of response. */
status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr ->nx_packet_length);
/* Valid response? */
if (status == NX_SUCCESS)
{
/* Is it an ACK response? */
if (dhcp_type == NX_DHCP_TYPE_DHCPACK)
{
/* Increment the number of ACKs received. */
interface_record -> nx_dhcp_acks_received++;
/* Update the parameters (IP address, server IP, lease, renewal and rebind times */
if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length))
break;
/* Set the IP address and gateway address from the value extracted from the Server's DHCP response. */
nx_ip_interface_address_set(ip_ptr, iface_index,
interface_record -> nx_dhcp_ip_address,
interface_record -> nx_dhcp_network_mask);
/* Check if the gateway address is valid. */
if (interface_record -> nx_dhcp_gateway_address)
{
/* Set the gateway address. */
nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address);
}
/* Lease has been renewed, set the countdown timer back to the renewal time and go back
to the Bound state. */
interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time;
/* Change to bound state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND;
}
else if (dhcp_type == NX_DHCP_TYPE_DHCPNACK)
{
/* Increment the number of NACKs received. */
interface_record -> nx_dhcp_nacks_received++;
/* Reinitialize DHCP. */
_nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index);
/* Restart DHCP service for this interface record. */
/* Start the DHCP protocol again by setting the state back to INIT. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT;
/* The client begins in INIT state and forms a DHCPDISCOVER message.
The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup.
RFC2131, Section4.4.1, Page36. */
/* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */
interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE;
interface_record -> nx_dhcp_rtr_interval = 0;
}
}
break;
}
default:
break;
} /* End of switch case */
/* Release the packet. */
nx_packet_release(new_packet_ptr);
/* Check if the state is changed. */
if (original_state != interface_record -> nx_dhcp_state)
{
/* Determine if the application has specified a routine for DHCP state change notification. */
if (dhcp_ptr -> nx_dhcp_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state);
}
/* Determine if the application has specified a routine for DHCP interface state change notification. */
if (dhcp_ptr -> nx_dhcp_interface_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state);
}
}
return;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_timeout_process PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is by the DHCP Client when it checks for a timer */
/* expiration event. It checks all the DHCP interface records who have */
/* started DHCP and updates the time remaining on their timeout. */
/* If a timeout has expired, this function then processes it according */
/* to the DHCP state it is in. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _nx_dhcp_send_request_internal Send a request to DHCP server */
/* _nx_dhcp_update_timeout Reset the DHCP timeout */
/* _nx_dhcp_add_randomize Modify timeout by random value*/
/* _nx_dhcp_update_renewal_timeout Set the retransmission timeout*/
/* _nx_arp_probe_send Send ARP probe for IP address */
/* uniqueness if ARP probe */
/* enabled */
/* nx_ip_interface_address_set Set the IP interface address */
/* nx_ip_gateway_address_set Set the IP gateway address */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_thread_entry */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _nx_dhcp_timeout_process(NX_DHCP *dhcp_ptr)
{
UINT i;
UINT original_state;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE
ULONG probing_delay;
NX_IP *ip_ptr;
/* Pickup the associated IP pointer. */
ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr;
#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */
/* Update the timeout on both interfaces. Check what needs to be done
if a timeout expires, based on Client state. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if the DHCP Client is active on this interface. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_FALSE)
continue;
/* Set the interface reocrd pointer. */
interface_record = &dhcp_ptr -> nx_dhcp_interface_record[i];
/* Update the count. */
interface_record -> nx_dhcp_seconds ++;
/* Check the timer. */
if (interface_record -> nx_dhcp_timeout != 0)
{
/* Apply the timer interval to the current DHCP Client timeout. */
if (interface_record -> nx_dhcp_timeout > NX_DHCP_TIME_INTERVAL)
{
/* Update the timeout. */
interface_record -> nx_dhcp_timeout -= (ULONG)NX_DHCP_TIME_INTERVAL;
}
else
{
/* The DHCP Client timeout has expired. */
interface_record -> nx_dhcp_timeout = 0;
/* Save the current state for state change callback. */
original_state = interface_record -> nx_dhcp_state;
/* Process according to what state the Client is in. */
switch (interface_record -> nx_dhcp_state)
{
case NX_DHCP_STATE_INIT:
{
/* Reset the seconds field for starting the DHCP address acquistiion. */
interface_record -> nx_dhcp_seconds = 0;
/* Initial state when there is no address. Send a DHCPDISCOVER message
to find a DHCP server and switch to the SELECTING state.
Initial timeout is NX_DHCP_MIN_RETRANS_TIMEOUT seconds. */
#ifndef NX_DHCP_ENABLE_BOOTP
/* Only if the DHCP Client is requesting an IP address and is configured to skip the Discovery message. */
if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) &&
(interface_record -> nx_dhcp_skip_discovery))
{
/* Send out the DHCP request. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST);
/* And change to the Requesting state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_REQUESTING;
}
else
{
/* Send out the DHCP request. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPDISCOVER);
/* And change to the Selecting state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_SELECTING;
}
#else
/* Send the BOOTP Request message. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_BOOT_REQUEST);
/* And change to the Requesting state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_REQUESTING;
#endif
/* Check if the retransmission interval is zero. */
if (interface_record -> nx_dhcp_rtr_interval == 0)
{
/* Set the interval to min retransmission timeout. */
interface_record -> nx_dhcp_rtr_interval = NX_DHCP_MIN_RETRANS_TIMEOUT;
}
else
{
/* Record the retransmission interval for next retransmission. */
interface_record -> nx_dhcp_rtr_interval = _nx_dhcp_update_timeout(interface_record -> nx_dhcp_rtr_interval);
}
/* Update the timeout for next retransmission. */
interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_rtr_interval;
/* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */
interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout);
/* Check if the timeout is zero. */
if (interface_record -> nx_dhcp_timeout == 0)
interface_record -> nx_dhcp_timeout = 1;
break;
}
case NX_DHCP_STATE_SELECTING:
{
#ifndef NX_DHCP_ENABLE_BOOTP
/* Retransmit the Discover message. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPDISCOVER);
#else
/* Retransmit the BOOTP Request message. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_BOOT_REQUEST);
#endif
/* Update the retransmision interval. */
interface_record -> nx_dhcp_rtr_interval = _nx_dhcp_update_timeout(interface_record -> nx_dhcp_rtr_interval);
/* Update the timeout for next retransmission. */
interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_rtr_interval;
/* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */
interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout);
/* Check if the timeout is zero. */
if (interface_record -> nx_dhcp_timeout == 0)
interface_record -> nx_dhcp_timeout = 1;
break;
}
case NX_DHCP_STATE_REQUESTING:
{
#ifndef NX_DHCP_ENABLE_BOOTP
/* Send a DHCP request. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST);
#else
/* Send a BOOTP request. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_BOOT_REQUEST);
#endif
/* Update the retransmision interval. */
interface_record->nx_dhcp_rtr_interval = _nx_dhcp_update_timeout(interface_record -> nx_dhcp_rtr_interval);
/* Reset the timeout for next retransmision. */
interface_record -> nx_dhcp_timeout = interface_record->nx_dhcp_rtr_interval;
/* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */
interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout);
/* Check if the timeout is zero. */
if (interface_record -> nx_dhcp_timeout == 0)
interface_record -> nx_dhcp_timeout = 1;
break;
}
case NX_DHCP_STATE_ADDRESS_PROBING:
{
#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE
/* Send the ARP probe. */
_nx_arp_probe_send(ip_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_ip_address);
/* Decrease the probe count. */
interface_record -> nx_dhcp_probe_count--;
/* Check the probe count. */
if (interface_record -> nx_dhcp_probe_count)
{
/* Calculate the delay time. */
probing_delay = (ULONG)NX_RAND() % (NX_DHCP_ARP_PROBE_MAX);
/* Determine if this is less than the minimum. */
if (probing_delay < NX_DHCP_ARP_PROBE_MIN)
{
/* Set the delay to the minimum. */
probing_delay = NX_DHCP_ARP_PROBE_MIN;
}
/* Check the probing_delay for timer interval. */
if (probing_delay)
interface_record -> nx_dhcp_timeout = probing_delay;
else
interface_record -> nx_dhcp_timeout = 1;
}
else
{
/* No address conflict. */
ip_ptr -> nx_ip_interface[interface_record -> nx_dhcp_interface_index].nx_interface_ip_conflict_notify_handler = NX_NULL;
/* Set the IP address. */
nx_ip_interface_address_set(ip_ptr, interface_record -> nx_dhcp_interface_index,
interface_record -> nx_dhcp_ip_address, interface_record -> nx_dhcp_network_mask);
/* Check if the gateway address is valid. */
if (interface_record -> nx_dhcp_gateway_address)
{
/* Set the gateway address. */
nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address);
}
/* Change to the Bound state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND;
#ifdef NX_DHCP_ENABLE_BOOTP
/* BOOTP does not use timeouts. For the life of this DHCP Client application, keep the same IP address. */
interface_record -> nx_dhcp_timeout = NX_WAIT_FOREVER;
#else
/* Set the renewal time received from the server. */
interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time;
#endif /* NX_DHCP_ENABLE_BOOTP */
}
#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */
break;
}
case NX_DHCP_STATE_BOUND:
{
/* Reset the seconds field for starting the DHCP request process. */
interface_record -> nx_dhcp_seconds = 0;
/* The lease has timed out. Time to renew. */
/* And change to the Renewing state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_RENEWING;
/* Send the renewal request. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST);
/* Set the time remaining based on RFC 2131 when T1 expires. */
interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_time;
interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time);
/* Record the retransmission interval. */
interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout;
break;
}
case NX_DHCP_STATE_RENEWING:
{
/* Check if we have reached the end of the renewal time. */
if (interface_record -> nx_dhcp_renewal_remain_time >= interface_record -> nx_dhcp_rtr_interval)
{
interface_record -> nx_dhcp_renewal_remain_time -= interface_record -> nx_dhcp_rtr_interval;
}
else
{
interface_record -> nx_dhcp_renewal_remain_time = 0;
}
/* Update the timeout for renew retranmission. */
interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time);
/* Check if we are at the limit on retransmission. */
if (interface_record -> nx_dhcp_timeout == 0)
{
/* And change to the Rebinding state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_REBINDING;
/* Send the rebind request. */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST);
/* Calculate the rebind time based on the RFC 2131. */
interface_record -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_lease_time - interface_record -> nx_dhcp_rebind_time;
/* Calculate the timeout for the response. */
interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time);
/* Record the retransmission interval. */
interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout;
}
else
{
/* Retransmit the Renewing message and wait again */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST);
/* Record the retransmission interval. */
interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout;
}
break;
}
case NX_DHCP_STATE_REBINDING:
{
/* No response yet, the response must have timed out,
update the timeout and check if we have reached the
end of the rebinding time. */
if (interface_record -> nx_dhcp_rebind_remain_time >= interface_record -> nx_dhcp_rtr_interval)
{
interface_record -> nx_dhcp_rebind_remain_time -= interface_record -> nx_dhcp_rtr_interval;
}
else
{
interface_record -> nx_dhcp_rebind_remain_time = 0;
}
/* Update the timeout for renew retranmission. */
interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time);
/* Check if we are at the limit on retransmission. */
if (interface_record -> nx_dhcp_timeout == 0)
{
/* Timeout. Restart DHCP service for this interface record. */
/* Reinitialize DHCP. */
_nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index);
/* Start the DHCP protocol again by setting the state back to INIT. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT;
/* The client begins in INIT state and forms a DHCPDISCOVER message.
The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup.
RFC2131, Section4.4.1, Page36. */
/* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */
interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE;
interface_record -> nx_dhcp_rtr_interval = 0;
}
else
{
/* Retransmit the Renewing message and wait again */
_nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST);
/* Record the retransmission interval. */
interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout;
}
break;
}
default:
{
break;
}
}
/* Check if the state is changed. */
if (original_state != interface_record -> nx_dhcp_state)
{
/* Determine if the application has specified a routine for DHCP state change notification. */
if (dhcp_ptr -> nx_dhcp_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state);
}
/* Determine if the application has specified a routine for DHCP interface state change notification. */
if (dhcp_ptr -> nx_dhcp_interface_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state);
}
}
} /* End of switch statement. */
}
} /* Try the next interface record. */
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_send_request PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking for the DHCP client send */
/* request service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* dhcp_message_type Type of DHCP message to send , */
/* */
/* OUTPUT */
/* NX_PTR_ERROR Invalid pointer input */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nxe_dhcp_send_request Actual send request service */
/* */
/* CALLED BY */
/* */
/* Application thread */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type)
{
UINT status;
/* Check for invalid input. */
if (!dhcp_ptr || (dhcp_message_type == 0) || (dhcp_message_type > NX_DHCP_TYPE_DHCPFORCERENEW))
{
return (NX_PTR_ERROR);
}
/* Call the actual service and return completion status. */
status = _nx_dhcp_send_request(dhcp_ptr, dhcp_message_type);
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_send_request PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sends the specified request to the first DHCP enabled */
/* interface found. To send a RELEASE or DECLINE message, use the */
/* nx_dhcp_release/nx_dhcp_interface_release or nx_dhcp_decline/ */
/* nx_dhcp_interface_decline respectively. */
/* */
/* To send a request on a specific DHCP interface if multiple */
/* interfaces are DHCP enabled, use the */
/* nx_dhcp_interface_send_request service. */
/* */
/* Note: Except for an INFORM REQUEST message, the application should */
/* not need to send DHCP messages out independently of the DHCP Client */
/* processing thread. It is not recommended to use this function once */
/* the DHCP Client has started until it is BOUND. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* dhcp_message_type Type of DHCP message to send */
/* */
/* OUTPUT */
/* */
/* status Actual completion status */
/* NX_DHCP_NO_INTERFACES_ENABLED No DHCP interface enabled */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_send_request Send DHCP request to server */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type)
{
UINT status;
UINT i;
/* Obtain the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER);
/* Find the DHCP interface record. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check which interface record is valid. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid)
{
/* Set the request on only the first (only) valid interface. */
status = _nx_dhcp_interface_send_request(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, dhcp_message_type);
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DHCP_NO_INTERFACES_ENABLED);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_send_request PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the send request service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to send message on */
/* dhcp_message_type DHCP messages to send: */
/* NX_DHCP_TYPE_DHCPDECLINE */
/* NX_DHCP_TYPE_DHCPRELEASE */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_send_request Actual send the DHCP request */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return(NX_PTR_ERROR);
}
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return(NX_INVALID_INTERFACE);
}
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
status = _nx_dhcp_interface_send_request(dhcp_ptr, iface_index, dhcp_message_type);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_send_request PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function allows the host application to send a specific request*/
/* on the specified interface. The interface must be enabled for DHCP. */
/* */
/* To send a RELEASE or DECLINE message on a specific interface, use */
/* the nx_dhcp_interface_release or nx_dhcp_interface_decline */
/* respectively. */
/* */
/* Note: Except for an INFORM REQUEST message, the application should */
/* not need to send DHCP messages out independently of the DHCP Client */
/* processing thread. It is not recommended to use this function once */
/* the DHCP Client has started until it is BOUND. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to send message on */
/* dhcp_message_type Type of DHCP message to send, */
/* NX_DHCP_TYPE_DHCPDECLINE */
/* NX_DHCP_TYPE_DHCPRELEASE */
/* */
/* OUTPUT */
/* */
/* NX_DHCP_INVALID_MESSAGE Message type not allowed */
/* status Actual completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_record_find Find Client record for the */
/* specified interface */
/* _nx_dhcp_send_request_internal Send the DHCP request */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type)
{
UINT status;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* If the message is a RELEASE or DECLINE request, the host should call nx_dhcp_release
or nx_dhcp_decline respectively. */
if ((dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE) || (dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE))
{
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return NX_DHCP_INVALID_MESSAGE;
}
/* The DHCP INFORM message is independent of the Client thread task activity. */
if (dhcp_message_type != NX_DHCP_TYPE_DHCPINFORM)
{
/* Determine if DHCP is started. */
if (dhcp_ptr -> nx_dhcp_interface_record[iface_index].nx_dhcp_state == NX_DHCP_STATE_NOT_STARTED)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* DHCP is not started so it should not 'send' a request to the server. */
return(NX_DHCP_NOT_STARTED);
}
}
status = _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, dhcp_message_type);
/* Release the DHCP mutex. */
tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_send_request_internal PORTABLE C */
/* 6.1.8 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sends a DHCP request to the server. Any additional */
/* options are appended to the request structure for certain types of */
/* DHCP requests. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to send message on */
/* dhcp_message_type Type of DHCP message to send */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* nx_packet_allocate Allocate a DHCP packet */
/* nx_packet_release Release DHCP packet */
/* nx_udp_socket_send Send DHCP packet */
/* _nx_dhcp_store_data Write data into message */
/* _nx_dhcp_add_option_value Add an option to the request */
/* _nx_dhcp_add_option_string Add an option string to the */
/* request */
/* _nx_dhcp_add_option_parameter_request Add a parameter request option*/
/* nx_udp_socket_interface_send Send packet out on interface */
/* _nx_dhcp_client_send_with_zero_source_address */
/* Send broadcast packet with */
/* zero source IP address */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_interface_send_request Send request on specified */
/* interface */
/* _nx_dhcp_interface_force_renew Send Force Renew message */
/* _nx_dhcp_interface_decline Send DECLINE message */
/* _nx_dhcp_interface_release Send RELEASE message */
/* _nx_dhcp_packet_process Process received packets */
/* _nx_dhcp_timeout_process Process timer expirations */
#ifdef NX_DHCP_CLIENT_RESTORE_STATE
/* _nx_dhcp_resume Resume the DHCP Client thread */
#endif
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 08-02-2021 Yuxin Zhou Modified comment(s), supported*/
/* adding additional request */
/* option in parameter request,*/
/* resulting in version 6.1.8 */
/* */
/**************************************************************************/
static UINT _nx_dhcp_send_request_internal(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UINT dhcp_message_type)
{
NX_PACKET *packet_ptr;
UCHAR *buffer;
ULONG targetIP;
UINT status;
ULONG dhcp_client_mac_msw;
ULONG dhcp_client_mac_lsw;
UINT iface_index;
UINT index = 0;
UCHAR *user_option_ptr;
UINT user_option_length;
UINT name_length;
/* Set the interface idnex. */
iface_index = interface_record -> nx_dhcp_interface_index;
/* Allocate a DHCP packet. */
status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &packet_ptr, NX_UDP_PACKET, NX_NO_WAIT);
/* Was the packet allocation successful? */
if (status != NX_SUCCESS)
{
/* Increment the DHCP internal error counter. */
interface_record -> nx_dhcp_internal_errors++;
/* Return status. */
return(status);
}
/* Set the interface index and MAC address. */
dhcp_client_mac_msw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw;
dhcp_client_mac_lsw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw;
/* Setup the buffer pointer. */
buffer = packet_ptr -> nx_packet_prepend_ptr;
/* Clear the buffer out... just in case. */
memset((void *) buffer, 0, NX_BOOTP_OFFSET_END);
/* Setup the standard BootP fields. */
buffer[NX_BOOTP_OFFSET_OP] = NX_BOOTP_OP_REQUEST;
buffer[NX_BOOTP_OFFSET_HTYPE] = NX_BOOTP_TYPE_ETHERNET;
buffer[NX_BOOTP_OFFSET_HLEN] = NX_BOOTP_HLEN_ETHERNET;
buffer[NX_BOOTP_OFFSET_HOPS] = 0;
buffer[NX_BOOTP_OFFSET_SERVER_NM] = 0;
buffer[NX_BOOTP_OFFSET_BOOT_FILE] = 0;
/* Setup the 'Xid' field. */
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_XID, 4, interface_record -> nx_dhcp_xid);
/* Set the 'secs' field according to RFC2131, Secion4.4.1, Page37, Table5. */
if ((dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE) || (dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE))
{
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SECS, 2, 0);
}
else
{
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SECS, 2, interface_record -> nx_dhcp_seconds);
}
/* Set the broadcast flag according to RFC2131, Secion4.4.1, Page38, Table5. */
/* Set the broadcast flag to 0 for DHCP Decline and DHCP Release. */
if ((dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE) || (dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE))
{
/* Request the response be sent unicast. */
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_FLAGS, 1, NX_BOOTP_FLAGS_UNICAST);
}
/* Set the 'broadcast' flag according to user requirement for DHCP Discover, DHCP Request and DHCP Inform. */
else if (interface_record -> nx_dhcp_clear_broadcast == NX_TRUE)
{
/* Request the response be sent unicast. */
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_FLAGS, 1, NX_BOOTP_FLAGS_UNICAST);
}
else
{
/* Request the response be sent broadcast. */
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_FLAGS, 1, NX_BOOTP_FLAGS_BROADCAST);
}
/* RFC 2131 4.4.1: Do not set the Client IP ("ciaddr" field) address...*/
if (dhcp_message_type != NX_DHCP_TYPE_DHCPINFORM)
{
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, NX_BOOTP_NO_ADDRESS);
}
/* ...unless this is an INFORM REQUEST message. */
else
{
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address);
}
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_YOUR_IP, 4, NX_BOOTP_NO_ADDRESS);
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SERVER_IP, 4, NX_BOOTP_NO_ADDRESS);
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_GATEWAY_IP, 4, NX_BOOTP_NO_ADDRESS);
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_HW, 2, dhcp_client_mac_msw);
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_HW + 2, 4, dhcp_client_mac_lsw);
#ifndef NX_DHCP_ENABLE_BOOTP
/* Update the index. */
index = NX_BOOTP_OFFSET_OPTIONS;
/* A BOOTP Client should not request DHCP option data. */
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_VENDOR, 4, NX_BOOTP_MAGIC_COOKIE);
/* Add the actual DHCP request. */
_nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, NX_DHCP_OPTION_DHCP_TYPE_SIZE, dhcp_message_type, &index);
#endif
/* Determine if any additional options need to be added relative to the DHCP message type.
RFC 2131, Table 5: Fields and options used by DHCP Clients. */
switch (dhcp_message_type)
{
#ifdef NX_DHCP_ENABLE_BOOTP
case NX_DHCP_TYPE_BOOT_REQUEST:
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address);
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SERVER_IP, 4, interface_record -> nx_dhcp_server_ip);
break;
#endif
case NX_DHCP_TYPE_DHCPDISCOVER:
/* Determine if we have a valid IP address. */
if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) &&
(interface_record -> nx_dhcp_ip_address != NX_BOOTP_BC_ADDRESS))
{
/* Add a IP request option if we have a valid IP address */
_nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_IP_REQ, NX_DHCP_OPTION_DHCP_IP_REQ_SIZE,
interface_record -> nx_dhcp_ip_address, &index);
}
/* Add an option request for an infinite lease. */
_nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_LEASE, NX_DHCP_OPTION_DHCP_LEASE_SIZE, NX_DHCP_INFINITE_LEASE, &index);
/* Add the system name */
if (dhcp_ptr -> nx_dhcp_name)
{
/* Check name length. */
if (_nx_utility_string_length_check(dhcp_ptr -> nx_dhcp_name, &name_length, 255))
{
nx_packet_release(packet_ptr);
return(NX_DHCP_INVALID_NAME);
}
_nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_HOST_NAME, name_length,
(UCHAR *) dhcp_ptr -> nx_dhcp_name, &index);
}
/* Add parameter request option. */
_nx_dhcp_add_option_parameter_request(dhcp_ptr, buffer, &index);
#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION
/* Add an option to specify the maximum length DHCP message that DHCP Client is willing to accept.
RFC2132, Section9.10, Page28. */
_nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_MAX_DHCP_MESSAGE, 2, dhcp_ptr -> nx_dhcp_max_dhcp_message_size, &index);
#endif
/* Increment the number of Discovery messages sent. */
interface_record -> nx_dhcp_discoveries_sent++;
break;
case NX_DHCP_TYPE_DHCPREQUEST:
/* Add the system name */
if (dhcp_ptr -> nx_dhcp_name)
{
/* Check name length. */
if (_nx_utility_string_length_check(dhcp_ptr -> nx_dhcp_name, &name_length, 255))
{
nx_packet_release(packet_ptr);
return(NX_DHCP_INVALID_NAME);
}
_nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_HOST_NAME, name_length, (UCHAR *) dhcp_ptr -> nx_dhcp_name, &index);
}
/* Determine if we have a valid IP address. Must not include if Renewing or Rebinding RCV 2131 4.3.2. */
if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) &&
(interface_record -> nx_dhcp_ip_address != NX_BOOTP_BC_ADDRESS) &&
(interface_record -> nx_dhcp_state != NX_DHCP_STATE_RENEWING) &&
(interface_record -> nx_dhcp_state != NX_DHCP_STATE_REBINDING))
{
/* Add an IP request option if we have a valid IP address. */
_nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_IP_REQ, NX_DHCP_OPTION_DHCP_IP_REQ_SIZE,
interface_record -> nx_dhcp_ip_address, &index);
}
/* Add a request for an infinite lease if we haven't already set the timers. */
if ((interface_record -> nx_dhcp_rebind_time == 0) ||
(interface_record -> nx_dhcp_renewal_time == 0))
{
/* Add the infinite lease option. */
_nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_LEASE, NX_DHCP_OPTION_DHCP_LEASE_SIZE, NX_DHCP_INFINITE_LEASE, &index);
}
/* Should add server ID if not renewing. */
if ((interface_record -> nx_dhcp_state != NX_DHCP_STATE_RENEWING) &&
(interface_record -> nx_dhcp_state != NX_DHCP_STATE_REBINDING) &&
(interface_record -> nx_dhcp_server_ip != NX_BOOTP_BC_ADDRESS)
)
{
/* Add Server identifier option. */
_nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_SERVER, NX_DHCP_OPTION_DHCP_SERVER_SIZE,
interface_record -> nx_dhcp_server_ip, &index);
}
else if ((interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING) ||
(interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING))
{
/* Ensure the renewal message fields are correct. */
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address);
}
/* Add parameter request option. */
_nx_dhcp_add_option_parameter_request(dhcp_ptr, buffer, &index);
#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION
/* Add an option to specify the maximum length DHCP message that DHCP Client is willing to accept.
RFC2132, Section9.10, Page28. */
_nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_MAX_DHCP_MESSAGE, 2, dhcp_ptr -> nx_dhcp_max_dhcp_message_size, &index);
#endif
/* Increment the number of Request messages sent. */
interface_record -> nx_dhcp_requests_sent++;
break;
case NX_DHCP_TYPE_DHCPDECLINE:
/* Does the Client have a nonzero requested address it is declining? */
if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) &&
(interface_record -> nx_dhcp_ip_address != NX_BOOTP_BC_ADDRESS))
{
/* Yes; add Request IP address option. */
_nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_IP_REQ, NX_DHCP_OPTION_DHCP_IP_REQ_SIZE,
interface_record -> nx_dhcp_ip_address, &index);
}
/* Add Server identifier option. */
_nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_SERVER, NX_DHCP_OPTION_DHCP_SERVER_SIZE,
interface_record -> nx_dhcp_server_ip, &index);
break;
case NX_DHCP_TYPE_DHCPRELEASE:
/* Added the 'ciaddr', Indicate the IP address being released. */
_nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address);
/* Add Server identifier option. */
_nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_SERVER, NX_DHCP_OPTION_DHCP_SERVER_SIZE,
interface_record -> nx_dhcp_server_ip, &index);
/* Increment the number of Release messages sent. */
interface_record -> nx_dhcp_releases_sent++;
break;
case NX_DHCP_TYPE_DHCPINFORM:
/* Add the system name */
if (dhcp_ptr -> nx_dhcp_name)
{
/* Check name length. */
if (_nx_utility_string_length_check(dhcp_ptr -> nx_dhcp_name, &name_length, 255))
{
nx_packet_release(packet_ptr);
return(NX_DHCP_INVALID_NAME);
}
_nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_HOST_NAME, name_length, (UCHAR *) dhcp_ptr -> nx_dhcp_name, &index);
}
/* Add parameter request option. */
_nx_dhcp_add_option_parameter_request(dhcp_ptr, buffer, &index);
/* Increment the number of Inform messages sent. */
interface_record -> nx_dhcp_informs_sent++;
break;
default:
break;
}
/* Add any user supplied options to the buffer. */
if (dhcp_ptr -> nx_dhcp_user_option_add)
{
/* Set the pointer for adding user option. */
user_option_ptr = buffer + index;
/* Calculate the available length for user options. Minus 1 to add the END option. */
user_option_length = (UINT)(packet_ptr -> nx_packet_data_end - user_option_ptr - 1);
/* Add the specific DHCP option user wanted. */
if (dhcp_ptr -> nx_dhcp_user_option_add(dhcp_ptr, iface_index, dhcp_message_type, user_option_ptr, &user_option_length) == NX_TRUE)
{
/* Update the index to include the user options. */
index += user_option_length;
}
else
{
/* Invalid user options. Release the packet. */
nx_packet_release(packet_ptr);
return(NX_DHCP_UNKNOWN_OPTION);
}
}
/* Setup the packet pointers. */
packet_ptr -> nx_packet_length = NX_BOOTP_OFFSET_END;
packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_BOOTP_OFFSET_END;
#ifndef NX_DHCP_ENABLE_BOOTP
/* Added the END option. */
*(buffer + index) = NX_DHCP_OPTION_END;
index ++;
/* Check the option length. */
if (index > NX_BOOTP_OFFSET_END)
{
packet_ptr -> nx_packet_length = index;
packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index;
}
#endif
/* Set the target address according to RFC2131, Section4.3.6, Page33, Table4 and Section4.4.4, Page40.
DHCP Request for renewing and DHCP Release message must be unicast. */
if (((dhcp_message_type == NX_DHCP_TYPE_DHCPREQUEST) && (interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING)) ||
(dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE))
{
/* Use the current server's IP address. */
targetIP = interface_record -> nx_dhcp_server_ip;
}
else
{
/* Set the server target IP address to broadcast. */
targetIP = NX_BOOTP_BC_ADDRESS;
}
/* DHCP messages broadcast by a client prior to that client obtaining
its IP address must have the source address field in the IP header
set to 0. RFC2131, Section4.1, Page23. */
if ((dhcp_message_type == NX_DHCP_TYPE_DHCPDISCOVER) ||
((dhcp_message_type == NX_DHCP_TYPE_DHCPREQUEST) && (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND)))
{
/* Call function to send the special packet with zero source address.*/
status = _nx_dhcp_client_send_with_zero_source_address(dhcp_ptr, iface_index, packet_ptr);
}
else
{
/* Send the packet. */
status = nx_udp_socket_interface_send(&(dhcp_ptr -> nx_dhcp_socket), packet_ptr, targetIP, NX_DHCP_SERVER_UDP_PORT, iface_index);
}
/* If an error is detected, release the packet. */
if (status != NX_SUCCESS)
{
/* Release the packet. */
nx_packet_release(packet_ptr);
}
/* Return completion status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_client_send_with_zero_source_address PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function builds the UDP and IP header with zero source address,*/
/* then sends the packet to the appropriate link driver. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to send message on */
/* packet_ptr Pointer to packet to send */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* (ip_link_driver) User supplied link driver */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_send_request_internal Send DHCP Request */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static UINT _nx_dhcp_client_send_with_zero_source_address(NX_DHCP *dhcp_ptr, UINT iface_index, NX_PACKET *packet_ptr)
{
NX_IP *ip_ptr;
NX_UDP_SOCKET *socket_ptr;
NX_UDP_HEADER *udp_header_ptr;
NX_IP_HEADER *ip_header_ptr;
NX_INTERFACE *interface_ptr;
ULONG ip_src_addr, ip_dest_addr;
UINT compute_checksum;
ULONG checksum;
ULONG val;
NX_IP_DRIVER driver_request;
/* Set up the pointer to the associated IP instance. */
ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr;
/* Set up the pointer to the associated socket. */
socket_ptr = &dhcp_ptr -> nx_dhcp_socket;
/* Set up the pointer to the interface. */
interface_ptr = &(ip_ptr -> nx_ip_interface[iface_index]);
packet_ptr -> nx_packet_ip_interface = interface_ptr;
/* Set up the address. */
ip_src_addr = NX_BOOTP_NO_ADDRESS;
ip_dest_addr = NX_BOOTP_BC_ADDRESS;
/* Check the interface. */
if ((!interface_ptr -> nx_interface_valid) || (!interface_ptr -> nx_interface_link_up))
{
/* None found; return the error status. */
return(NX_INVALID_INTERFACE);
}
/* Build UDP header. */
/* Prepend the UDP header to the packet. First, make room for the UDP header. */
packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER);
#ifndef NX_DISABLE_UDP_INFO
/* Increment the total UDP packets sent count. */
ip_ptr -> nx_ip_udp_packets_sent++;
/* Increment the total UDP bytes sent. */
ip_ptr -> nx_ip_udp_bytes_sent += packet_ptr -> nx_packet_length;
/* Increment the total UDP packets sent count for this socket. */
socket_ptr -> nx_udp_socket_packets_sent++;
/* Increment the total UDP bytes sent for this socket. */
socket_ptr -> nx_udp_socket_bytes_sent += packet_ptr -> nx_packet_length;
#endif
/* Increase the packet length. */
packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + (ULONG)sizeof(NX_UDP_HEADER);
/* Setup the UDP header pointer. */
udp_header_ptr = (NX_UDP_HEADER *) packet_ptr -> nx_packet_prepend_ptr;
/* Build the first 32-bit word of the UDP header. */
udp_header_ptr -> nx_udp_header_word_0 = (((ULONG)socket_ptr -> nx_udp_socket_port ) << NX_SHIFT_BY_16) | (ULONG) NX_DHCP_SERVER_UDP_PORT;
/* Build the second 32-bit word of the UDP header. */
udp_header_ptr -> nx_udp_header_word_1 = (packet_ptr -> nx_packet_length << NX_SHIFT_BY_16);
/* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will
swap the endian of the UDP header. */
NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
#ifdef NX_DISABLE_UDP_TX_CHECKSUM
compute_checksum = 0;
#else /* NX_DISABLE_UDP_TX_CHECKSUM */
compute_checksum = 1;
#endif /* NX_DISABLE_UDP_TX_CHECKSUM */
if (compute_checksum)
{
/* Yes, we need to compute the UDP checksum. */
checksum = _nx_dhcp_client_checksum_compute(packet_ptr,
17,
(UINT)packet_ptr -> nx_packet_length,
&ip_src_addr,
&ip_dest_addr);
checksum = ~checksum & NX_LOWER_16_MASK;
/* If the computed checksum is zero, it will be transmitted as all ones. */
/* RFC 768, page 2. */
if (checksum == 0)
checksum = 0xFFFF;
NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum;
NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
}
/* Get mutex protection. */
tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
/* Build the IP header. */
/* Prepend the IP header to the packet. First, make room for the IP header. */
packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - 20;
/* Increase the packet length. */
packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + 20;
/* Setup the IP header pointer. */
ip_header_ptr = (NX_IP_HEADER *) packet_ptr -> nx_packet_prepend_ptr;
/* Build the first 32-bit word of the IP header. */
ip_header_ptr -> nx_ip_header_word_0 = (NX_IP_VERSION | socket_ptr -> nx_udp_socket_type_of_service | (0xFFFF & packet_ptr -> nx_packet_length));
/* Build the second 32-bit word of the IP header. */
ip_header_ptr -> nx_ip_header_word_1 = (ip_ptr -> nx_ip_packet_id++ << NX_SHIFT_BY_16) | socket_ptr -> nx_udp_socket_fragment_enable;
/* Build the third 32-bit word of the IP header. */
ip_header_ptr -> nx_ip_header_word_2 = ((socket_ptr -> nx_udp_socket_time_to_live << NX_IP_TIME_TO_LIVE_SHIFT) | NX_IP_UDP);
/* Place the source IP address in the IP header. */
ip_header_ptr -> nx_ip_header_source_ip = ip_src_addr;
/* Place the destination IP address in the IP header. */
ip_header_ptr -> nx_ip_header_destination_ip = ip_dest_addr;
/* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will
swap the endian of the IP header. */
NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0);
NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2);
NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip);
NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
#ifdef NX_DISABLE_IP_TX_CHECKSUM
compute_checksum = 0;
#else /* NX_DISABLE_IP_TX_CHECKSUM */
compute_checksum = 1;
#endif /* NX_DISABLE_IP_TX_CHECKSUM */
if (compute_checksum)
{
checksum = _nx_dhcp_client_checksum_compute(packet_ptr, 4, 20, NULL, NULL);
val = (ULONG)(~checksum);
val = val & NX_LOWER_16_MASK;
/* Convert to network byte order. */
NX_CHANGE_ULONG_ENDIAN(val);
/* Now store the checksum in the IP header. */
ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | val;
}
#ifdef NX_ENABLE_IP_PACKET_FILTER
/* Check if the IP packet filter is set. */
if (ip_ptr -> nx_ip_packet_filter)
{
/* Yes, call the IP packet filter routine. */
if ((ip_ptr -> nx_ip_packet_filter((VOID *)(ip_header_ptr), NX_IP_PACKET_OUT)) != NX_SUCCESS)
{
/* Release mutex protection. */
tx_mutex_put(&(ip_ptr -> nx_ip_protection));
/* Return a not successful status. */
return(NX_NOT_SUCCESSFUL);
}
}
#endif /* NX_ENABLE_IP_PACKET_FILTER */
/* Build the driver request. */
driver_request.nx_ip_driver_ptr = ip_ptr;
driver_request.nx_ip_driver_packet = packet_ptr;
driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_ip_interface;
driver_request.nx_ip_driver_command = NX_LINK_PACKET_BROADCAST;
driver_request.nx_ip_driver_physical_address_msw = 0xFFFFUL;
driver_request.nx_ip_driver_physical_address_lsw = 0xFFFFFFFFUL;
/* Determine if fragmentation is needed. */
if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_mtu_size)
{
#ifndef NX_DISABLE_FRAGMENTATION
/* Check the DF bit flag. */
if ((ip_ptr -> nx_ip_fragment_processing) && (socket_ptr -> nx_udp_socket_fragment_enable != NX_DONT_FRAGMENT))
{
/* Fragmentation is needed, call the IP fragment processing routine. */
(ip_ptr -> nx_ip_fragment_processing) (&driver_request);
/* Release mutex protection. */
tx_mutex_put(&(ip_ptr -> nx_ip_protection));
/* Return a successful status. */
return(NX_SUCCESS);
}
else
#endif /* NX_DISABLE_FRAGMENTATION */
{
#ifndef NX_DISABLE_IP_INFO
/* Increment the IP send packets dropped count. */
ip_ptr -> nx_ip_send_packets_dropped++;
#endif
/* Release mutex protection. */
tx_mutex_put(&(ip_ptr -> nx_ip_protection));
/* Return a not successful status. */
return(NX_NOT_SUCCESSFUL);
}
}
#ifndef NX_DISABLE_IP_INFO
/* Increment the IP packet sent count. */
ip_ptr -> nx_ip_total_packets_sent++;
/* Increment the IP bytes sent count. */
ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - 20;
#endif
/* Broadcast packet. */
(packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request);
/* Release mutex protection. */
tx_mutex_put(&(ip_ptr -> nx_ip_protection));
/* Return a successful status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_client_checksum_compute PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function computes the checksum from the supplied packet */
/* pointer and IP address fields required for the pseudo header. */
/* */
/* INPUT */
/* */
/* packet_ptr Pointer to packet */
/* protocol Protocol type */
/* data_length Size of the protocol payload */
/* src_ip_addr IPv4 source address */
/* dest_ip_addr IPv4 destination address */
/* */
/* OUTPUT */
/* */
/* computed checksum */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* NetX Duo internal routines */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static USHORT _nx_dhcp_client_checksum_compute(NX_PACKET *packet_ptr, ULONG protocol,
UINT data_length, ULONG* src_ip_addr,
ULONG* dest_ip_addr)
{
ULONG checksum = 0;
USHORT tmp;
USHORT *short_ptr;
ULONG *long_ptr;
ULONG packet_size;
NX_PACKET *current_packet;
ULONG *end_ptr;
/* For computing UDP(17), we need to include the pseudo header. */
if (protocol == 17)
{
USHORT *src_ip_short, *dest_ip_short;
checksum = protocol;
src_ip_short = (USHORT*)src_ip_addr;
dest_ip_short = (USHORT*)dest_ip_addr;
checksum += src_ip_short[0];
checksum += src_ip_short[1];
checksum += dest_ip_short[0];
checksum += dest_ip_short[1];
/* Take care of data length */
checksum += data_length;
/* Fold a 4-byte value into a two byte value */
checksum = (checksum >> 16) + (checksum & 0xFFFF);
/* Do it again in case previous operation generates an overflow */
checksum = (checksum >> 16) + (checksum & 0xFFFF);
/* Convert to network byte order. */
tmp = (USHORT)checksum;
NX_CHANGE_USHORT_ENDIAN(tmp);
checksum = tmp;
}
/* Now we need to go through the payloads */
/* Setup the pointer to the start of the packet. */
long_ptr = (ULONG *) packet_ptr -> nx_packet_prepend_ptr;
/* Initialize the current packet to the input packet pointer. */
current_packet = packet_ptr;
/* Loop the packet. */
while (current_packet)
{
/* Calculate current packet size. */
packet_size = (ULONG)(current_packet -> nx_packet_append_ptr - current_packet -> nx_packet_prepend_ptr);
/* Calculate the end address in this packet. */
if (data_length > (UINT)packet_size)
{
end_ptr = (ULONG *)(((ULONG)current_packet -> nx_packet_append_ptr) & (ULONG)(~3));
}
else
{
end_ptr = (ULONG *)(current_packet -> nx_packet_prepend_ptr + data_length - 3);
}
/* Set the start address in this packet. */
long_ptr = (ULONG *)current_packet -> nx_packet_prepend_ptr;
if (long_ptr < end_ptr)
{
/* Calculate the data_length. */
data_length -= (((ULONG)end_ptr + 3) & (ULONG)(~3)) - (ULONG)long_ptr;
/* Loop to calculate the packet's checksum. */
while (long_ptr < end_ptr)
{
checksum += (*long_ptr & NX_LOWER_16_MASK);
checksum += (*long_ptr >> NX_SHIFT_BY_16);
long_ptr++;
}
}
/* Determine if we are at the end of the current packet. */
if ((data_length > 0) && (current_packet -> nx_packet_next))
{
/* Is append_ptr two bytes aligned but not four bytes aligned? */
if ((((ULONG)current_packet -> nx_packet_append_ptr) & 3) == 2)
{
/* Yes it is. Process the last two bytes in chaining packets. */
short_ptr = (USHORT *)long_ptr;
checksum += *short_ptr;
data_length -= 2;
}
/* We have crossed the packet boundary. Move to the next packet
structure. */
current_packet = current_packet -> nx_packet_next;
}
else
{
break;
}
}
/* Determine if there is only one byte left. */
if (data_length)
{
/* Set the short_ptr. */
short_ptr = (USHORT *)(long_ptr);
/* Check the data length. */
if (data_length == 1)
{
*((UCHAR *)short_ptr + 1) = 0;
}
else if (data_length == 3)
{
checksum += *short_ptr;
short_ptr++;
*((UCHAR *)short_ptr + 1) = 0;
}
checksum += *short_ptr;
}
/* Fold a 4-byte value into a two byte value */
checksum = (checksum >> 16) + (checksum & 0xFFFF);
/* Do it again in case previous operation generates an overflow */
checksum = (checksum >> 16) + (checksum & 0xFFFF);
/* Convert to host byte order. */
tmp = (USHORT)checksum;
NX_CHANGE_USHORT_ENDIAN(tmp);
/* Return the computed checksum. */
return(tmp);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_extract_information PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function extracts important information from the server's */
/* response DHCP message. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* interface_record Pointer to DHCP interface */
/* dhcp_message Pointer to DHCP message */
/* length Size of DHCP message buffer */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_ip_address_set Set the DHCP IP address */
/* nx_ip_gateway_address_set Set the Gateway address */
/* _nx_dhcp_get_option_value Get DHCP option from buffer */
/* _nx_dhcp_get_data Get data from buffer */
/* memcpy Copy specified area of memory */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_packet_process Data received handler */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), and */
/* verified memcpy use cases, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static UINT _nx_dhcp_extract_information(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UCHAR *dhcp_message, UINT length)
{
ULONG value;
/* Extract the IP address. */
value = _nx_dhcp_get_data(dhcp_message + NX_BOOTP_OFFSET_YOUR_IP, 4);
/* Determine if it is valid. */
if ((value != NX_BOOTP_NO_ADDRESS) &&
(((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) ||
((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) ||
((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE)))
{
/* Store the IP address. */
interface_record -> nx_dhcp_ip_address = value;
}
else
{
return(NX_DHCP_BAD_IP_ADDRESS);
}
/* Determine if there is a subnet mask. Note a DHCP Server receiving a BOOTP request
may send DHCP option data for subnet masks as per RFC 1534 Section 2. */
if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_SUBNET_MASK, &value, length) == NX_SUCCESS)
{
/* Make sure there is a valid IP address too. */
if (value != NX_BOOTP_NO_ADDRESS)
{
interface_record -> nx_dhcp_network_mask = value;
}
else
{
ULONG ip_address;
/* No valid network mask info supplied; use the current network mask if any. Don't
care about current IP address for now. */
nx_ip_interface_address_get(dhcp_ptr -> nx_dhcp_ip_ptr,
interface_record -> nx_dhcp_interface_index,
&ip_address,
&(interface_record -> nx_dhcp_network_mask));
}
}
#ifdef NX_DHCP_ENABLE_BOOTP
/* Update the IP address. */
value = _nx_dhcp_get_data(dhcp_message + NX_BOOTP_OFFSET_SERVER_IP, 4);
/* Determine if it is valid. */
if (value != NX_BOOTP_NO_ADDRESS)
{
/* Store the IP address. */
interface_record -> nx_dhcp_server_ip = value;
}
/* Update the IP address. */
value = _nx_dhcp_get_data(dhcp_message + NX_BOOTP_OFFSET_GATEWAY_IP, 4);
/* Determine if it is valid. */
if ((value != NX_BOOTP_NO_ADDRESS) &&
(((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) ||
((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) ||
((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE)))
{
/* Store the gateway/Router IP address to the Client record. */
interface_record -> nx_dhcp_gateway_address = value;
}
else
{
/* The gateway may be sent as an option: See note above about BOOTP Clients
parsing DHCP option data. */
/* Determine if the IP gateway/router IP address is present. */
if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_GATEWAYS, &value, length) == NX_SUCCESS)
{
/* Determine if it is valid. */
if ((value != NX_BOOTP_NO_ADDRESS) &&
(((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) ||
((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) ||
((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE)))
{
/* Store the gateway/Router IP address to the Client record. */
interface_record -> nx_dhcp_gateway_address = value;
}
else
{
return(NX_DHCP_BAD_IP_ADDRESS);
}
}
}
#else
/* NX_DHCP_ENABLE_BOOTP not defined */
/* Overwrite the server ID if there is a DHCP option for Server ID */
if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_DHCP_SERVER, &value, length) == NX_SUCCESS)
{
/* Determine if it is valid. */
if ((value != NX_BOOTP_NO_ADDRESS) &&
(((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) ||
((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) ||
((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE)))
{
/* Store the server IP address. */
interface_record -> nx_dhcp_server_ip = value;
}
else
{
return(NX_DHCP_BAD_IP_ADDRESS);
}
}
/* Get the lease time. */
if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_DHCP_LEASE, &value, length) == NX_SUCCESS)
{
/* Check for an infinite lease. */
if (value == 0xFFFFFFFF)
{
/* Store the 'infinite' lease time . */
interface_record -> nx_dhcp_lease_time = value;
interface_record -> nx_dhcp_renewal_time = value;
interface_record -> nx_dhcp_rebind_time = value;
}
else
{
/* Store the lease time in timer ticks. */
interface_record -> nx_dhcp_lease_time = value * (ULONG)NX_IP_PERIODIC_RATE;
/* Set the renew and rebind times. */
interface_record -> nx_dhcp_renewal_time = interface_record -> nx_dhcp_lease_time / 2;
interface_record -> nx_dhcp_rebind_time = interface_record -> nx_dhcp_lease_time - (interface_record -> nx_dhcp_lease_time / 8);
}
}
/* Overwrite the renew and rebind times with the specified values if the options are present. */
if ((_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_RENEWAL, &value, length) == NX_SUCCESS) &&
(value <= interface_record -> nx_dhcp_lease_time))
{
/* Check for an infinite lease. */
if (value == 0xFFFFFFFF)
{
/* Set the 'infinite least time. */
interface_record -> nx_dhcp_renewal_time = value;
}
else
{
/* Store the renewal time in timer ticks */
interface_record -> nx_dhcp_renewal_time = value * (ULONG)NX_IP_PERIODIC_RATE;
}
}
/* Determine if there is a rebind time. */
if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_REBIND, &value, length) == NX_SUCCESS)
{
/* Check for an infinite lease. */
if (value == 0xFFFFFFFF)
{
/* Set the 'infinite least time. */
interface_record -> nx_dhcp_rebind_time = value;
}
else
{
/* Convert to timer ticks. */
value = value * (ULONG)NX_IP_PERIODIC_RATE;
/* Sanity check*/
if ((value <= interface_record -> nx_dhcp_lease_time) &&
(value >= interface_record -> nx_dhcp_renewal_time))
{
/* Store the rebind time. */
interface_record -> nx_dhcp_rebind_time = value;
}
}
}
/* Determine if this is an ACK from a server response, which can only happen from a handful of states. */
if ((interface_record -> nx_dhcp_state == NX_DHCP_STATE_REQUESTING) ||
(interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING) ||
(interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING))
{
/* Determine if the IP gateway/router IP address is present. */
if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_GATEWAYS, &value, length) == NX_SUCCESS)
{
/* Determine if it is valid. */
if ((value != NX_BOOTP_NO_ADDRESS) &&
(((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) ||
((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) ||
((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE)))
{
/* Store the gateway/Router IP address to the Client record. */
interface_record -> nx_dhcp_gateway_address = value;
}
else
{
return(NX_DHCP_BAD_IP_ADDRESS);
}
}
}
/* Check the DHCP options size. */
if ((length - NX_BOOTP_OFFSET_OPTIONS) > NX_DHCP_OPTIONS_BUFFER_SIZE)
interface_record -> nx_dhcp_options_size = NX_DHCP_OPTIONS_BUFFER_SIZE;
else
interface_record -> nx_dhcp_options_size = length - NX_BOOTP_OFFSET_OPTIONS;
/* Copy the DHCP options into DHCP Client options buffer. */
memcpy(interface_record -> nx_dhcp_options_buffer, /* Use case of memcpy is verified. */
&dhcp_message[NX_BOOTP_OFFSET_OPTIONS], interface_record -> nx_dhcp_options_size);
#endif /* NX_DHCP_ENABLE_BOOTP */
return (NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_get_option_value PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function searches through a buffer containing a BootP message */
/* for a DHCP option parameter and gets the value of that option if */
/* it exists. The function is restricted to options that are less */
/* than 4 octets (bytes) in size. */
/* */
/* INPUT */
/* */
/* bootp_message Pointer to option buffer */
/* option Option requested */
/* value Pointer to return value var */
/* length Size of option buffer */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_search_buffer Search the buffer */
/* _nx_dhcp_get_data Get data from buffer */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_packet_process Data received handler */
/* _nx_dhcp_extract_information Extract info from server */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static UINT _nx_dhcp_get_option_value(UCHAR *bootp_message, UINT option, ULONG *value, UINT length)
{
UCHAR *data;
UCHAR *option_message;
UINT option_length;
/* Setup buffer pointer. */
option_message = &bootp_message[NX_BOOTP_OFFSET_OPTIONS];
option_length = length - NX_BOOTP_OFFSET_OPTIONS;
/* Find the option. */
if ((option != NX_DHCP_OPTION_PAD) && (option != NX_DHCP_OPTION_END))
{
/* Search the buffer for the option. */
data = _nx_dhcp_search_buffer(option_message, option, option_length);
/* Check to see if the option was found. */
if (data != NX_NULL)
{
/* Check for the proper size. */
if (*data > 4)
{
/* Check for the gateway option. */
if (option == NX_DHCP_OPTION_GATEWAYS)
{
/* Pickup the first gateway address. */
*value = _nx_dhcp_get_data(data + 1, 4);
/* For now, just disregard any additional gateway addresses. */
return(NX_SUCCESS);
}
else
{
/* Invalid size, return error. */
return(NX_SIZE_ERROR);
}
}
else
{
/* Get the actual value. */
*value = _nx_dhcp_get_data(data + 1, *data);
return(NX_SUCCESS);
}
}
}
/* Return an error if not found. */
return(NX_OPTION_ERROR);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_add_option_value PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This routine adds a DHCP vendor option value to the BootP message */
/* in the supplied buffer. Adding the option includes adding the */
/* option code, length and option data value. */
/* */
/* INPUT */
/* */
/* bootp_message Pointer to message buffer */
/* option Option to add */
/* value Value of Option to add */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_store_data Store data value */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_send_request_internal Send DHCP request */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_add_option_value(UCHAR *bootp_message, UINT option, UINT size, ULONG value, UINT *index)
{
/* Store the option. */
*(bootp_message + (*index)) = (UCHAR)option;
(*index) ++;
/* Store the option size. */
*(bootp_message + (*index)) = (UCHAR)size;
(*index) ++;
/* Store the option value. */
_nx_dhcp_store_data(bootp_message + (*index), size, value);
(*index) += size;
/* Return a successful completion. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_add_option_string PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This routine adds a DHCP option string to the BootP message in */
/* supplied buffer. Adding the option includes adding the option */
/* code, length and option string. */
/* */
/* INPUT */
/* */
/* bootp_message Pointer to message buffer */
/* option Option to add */
/* size Size of option string */
/* value Option string pointer */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_move_string Store option string */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_send_request_internal Internal DHCP message send */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static UINT _nx_dhcp_add_option_string(UCHAR *bootp_message, UINT option, UINT size, UCHAR *value, UINT *index)
{
/* Store the option. */
*(bootp_message + (*index)) = (UCHAR)option;
(*index) ++;
/* Store the option size. */
*(bootp_message + (*index)) = (UCHAR)size;
(*index) ++;
/* Store the option value. */
_nx_dhcp_move_string(bootp_message + (*index), value, size);
(*index) += size;
/* Return a successful completion. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_add_option_parameter_request PORTABLE C */
/* 6.1.8 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This routine adds a DHCP parameter request option to the BootP */
/* message in supplied buffer. Adding the option includes adding the */
/* option code, length and option value. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* bootp_message Pointer to message buffer */
/* index Index to write data */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_move_string Store option string */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_send_request_internal Internal DHCP message send */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 08-02-2021 Yuxin Zhou Initial Version 6.1.8 */
/* */
/**************************************************************************/
static UINT _nx_dhcp_add_option_parameter_request(NX_DHCP *dhcp_ptr, UCHAR *bootp_message, UINT *index)
{
/* Store the option. */
*(bootp_message + (*index)) = NX_DHCP_OPTION_DHCP_PARAMETERS;
(*index) ++;
/* Store the option size. */
*(bootp_message + (*index)) = (UCHAR)(NX_DHCP_REQUEST_PARAMETER_SIZE + dhcp_ptr -> nx_dhcp_user_request_parameter_size);
(*index) ++;
/* Store the option value. */
_nx_dhcp_move_string(bootp_message + (*index), _nx_dhcp_request_parameters, NX_DHCP_REQUEST_PARAMETER_SIZE);
(*index) += (UINT)NX_DHCP_REQUEST_PARAMETER_SIZE;
/* Check if there are additional user options. */
if (dhcp_ptr -> nx_dhcp_user_request_parameter_size)
{
_nx_dhcp_move_string(bootp_message + (*index), dhcp_ptr -> nx_dhcp_user_request_parameter, dhcp_ptr -> nx_dhcp_user_request_parameter_size);
(*index) += (UCHAR)dhcp_ptr -> nx_dhcp_user_request_parameter_size;
}
/* Return a successful completion. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_add_randomize PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This routine adds randomized variance to the input timeout up to */
/* +/- one second. */
/* */
/* INPUT */
/* */
/* timeout Timeout to randomize */
/* */
/* OUTPUT */
/* */
/* ULONG Modified timeout value */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* nx_dhcp_process Process the current state of */
/* the DHCP Client state machine*/
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static ULONG _nx_dhcp_add_randomize(ULONG timeout)
{
ULONG adjustment;
/* Uniform random number chosen from the range -1 to +1 second as recommended by RFC2131, Section4.1, Page24. */
/* Calculate random time adjustment in timer ticks from the range 0 to NX_IP_PERIODIC_RATE * 2. */
adjustment = (ULONG)NX_RAND() % ((NX_IP_PERIODIC_RATE << 1) + 1);
/* Check for adjustment. */
if (adjustment < NX_IP_PERIODIC_RATE)
{
/* Updated timeout, minus NX_IP_PERIODIC_RATE - adjustment. */
/* Check for timeout. */
if (timeout > (NX_IP_PERIODIC_RATE - adjustment))
timeout -= (ULONG)(NX_IP_PERIODIC_RATE - adjustment);
else
timeout = 0;
}
else
{
/* Updated timeout, add adjustment- NX_IP_PERIODIC_RATE. */
timeout += (ULONG)(adjustment - NX_IP_PERIODIC_RATE);
}
return timeout;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_update_timeout PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function updates the DHCP timeout for retransmission. When the */
/* current timeout expires, this function doubles the timeout, but */
/* limits the timeout value to NX_DHCP_MAX_RETRANS_TIMEOUT (seconds). */
/* */
/* INPUT */
/* */
/* timeout The current Timeout value */
/* */
/* OUTPUT */
/* */
/* timeout The updated timeout */
/* */
/* CALLS */
/* */
/* _nx_dhcp_convert_delay_to_ticks Convert the delay to ticks */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_timeout_process Timer expiration handler */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static ULONG _nx_dhcp_update_timeout(ULONG timeout)
{
/* Timed out, double the timeout, limited to NX_DHCP_MAX_RETRANS_TIMEOUT */
if ((2 * timeout) >= NX_DHCP_MAX_RETRANS_TIMEOUT)
{
/* Set the timeout as NX_DHCP_MAX_RETRANS_TIMEOUT. */
timeout = NX_DHCP_MAX_RETRANS_TIMEOUT;
}
else
{
/* Double timeout value. */
timeout = timeout * 2;
}
/* Return the sequence timeout. */
return(timeout);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_update_renewal_timeout PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function updates the DHCP timeout when trying to renew a */
/* lease according to the RFC. When the current period has timed out, */
/* this function halves the timeout, limiting the minimum timeout */
/* value to NX_DHCP_MIN_RENEW_TIMEOUT seconds. */
/* */
/* INPUT */
/* */
/* timeout The current Timeout value */
/* */
/* OUTPUT */
/* */
/* timeout Renewal time remaining */
/* */
/* CALLS */
/* */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_client_interface_update_time_remaining */
/* Apply input time elapsed to */
/* the DHCP Client record */
/* _nx_dhcp_timeout_process Timer expiration handler */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static ULONG _nx_dhcp_update_renewal_timeout(ULONG timeout)
{
/* check if the timeout is non zero */
if (timeout != 0)
{
/* Timed out, halve the timeout, limited to NX_DHCP_MIN_RENEW_TIMEOUT or
the remaining timeout if it is less than NX_DHCP_MIN_RENEW_TIMEOUT */
if (timeout > NX_DHCP_MIN_RENEW_TIMEOUT)
{
/* Timeout can still decrease, either
force it to the minimum or halve it */
if (timeout > (2 * NX_DHCP_MIN_RENEW_TIMEOUT ))
{
/* Halve timeout. */
timeout = timeout / 2;
}
else
{
/* set timeout to minimum. */
timeout = NX_DHCP_MIN_RENEW_TIMEOUT ;
}
}
}
/* Return the sequence timeout. */
return(timeout);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_search_buffer PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This routine searches through a buffer containing a BootP message */
/* for a DHCP option parameter and returns a pointer to the byte */
/* containing the size of the data section of that option if it */
/* exists. If the option cannot be found then function returns NULL. */
/* If the option has no data (PAD and END) then the pointer is not */
/* usable. */
/* */
/* INPUT */
/* */
/* option_message Pointer to option buffer area */
/* option Option to search for */
/* length Length of search buffer */
/* */
/* OUTPUT */
/* */
/* pointer Pointer to found option */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_get_option_value Get the value of an option */
/* _nx_dhcp_get_option_data Get the string of an option */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static UCHAR *_nx_dhcp_search_buffer(UCHAR *option_message, UINT option, UINT length)
{
UCHAR *data;
UINT i;
UINT size;
/* Setup buffer pointer. */
data = option_message;
i = 0;
/* Search as long as there are valid options. */
while (i < length - 1)
{
/* Simply skip any padding */
if (*data == NX_DHCP_OPTION_PAD)
{
data++;
i++;
}
/* On a match, return a pointer to the size. */
else if (*data == option)
{
size = *(data + 1);
/* Check if the option data is in the packet. */
if ((i + size + 1) > length)
return(NX_NULL);
/* Return a pointer to the option size byte. */
return(data + 1);
}
/* Otherwise skip the option by adding the size to the pointer. */
else
{
size = *(++data);
/* skip the data plus the size byte */
data += size + 1;
i += size + 1;
}
}
/* Return NULL to indicate the option was not found. */
return(NX_NULL);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_get_data PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This routine gets a data value from a buffer, assuming the data is */
/* stored in standard Network format (big endian). Up to 4 bytes of */
/* data are used, if there are more than 4 bytes, only the lower 4 */
/* bytes are returned. */
/* */
/* INPUT */
/* */
/* data Pointer to buffer data */
/* size Size of data value */
/* */
/* OUTPUT */
/* */
/* value Data value retrieved */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_get_response Get response from server */
/* _nx_dhcp_extract_information Extract server information */
/* _nx_dhcp_get_option_value Retrieve option value */
/* _nx_dhcp_update_address_list Update address list */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static ULONG _nx_dhcp_get_data(UCHAR *data, UINT size)
{
ULONG value = 0;
/* Process the data retrieval request. */
while (size-- > 0)
{
/* Build return value. */
value = (value << 8) | *data++;
}
/* Return value. */
return(value);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_store_data PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function stores a data value in a buffer in standard Network */
/* format (big endian) where the destination may be unaligned. Up to */
/* 4 bytes of data are stored, if the size is larger than 4 bytes, the */
/* remaining bytes are set to zero. */
/* */
/* INPUT */
/* */
/* data Pointer to buffer data */
/* size Size of data value */
/* value Value to store */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_send_request_internal Send DHCP request */
/* _nx_dhcp_add_option_value Add a DHCP option */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static VOID _nx_dhcp_store_data(UCHAR *data, UINT size, ULONG value)
{
/* Make sure that data is left justified. */
switch (size)
{
case 1:
value <<= 24;
break;
case 2:
value <<= 16;
break;
case 3:
value <<= 8;
break;
default:
break;
}
/* Store the value. */
while (size-- > 0)
{
*data = (UCHAR) ((value >> 24) & 0xff);
data++;
value <<= 8;
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_move_string PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function stores a sequence of data bytes to a buffer. */
/* */
/* INPUT */
/* */
/* dest Pointer to destination buffer */
/* source Pointer to source buffer */
/* size Number of bytes to move */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_add_option_string Add option string */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static VOID _nx_dhcp_move_string(UCHAR *dest, UCHAR *source, UINT size)
{
/* Loop to copy all bytes. */
while (size-- > 0)
{
/* Copy a byte. */
*dest++ = *source++;
}
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_server_address_get PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking for the DHCP server get */
/* service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP Client task */
/* server_address Pointer to DHCP server address */
/* */
/* OUTPUT */
/* */
/* NX_PTR_ERROR Invalid pointer input */
/* status Actual completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_server_address_get Actual get DHCP IP server */
/* address service */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address)
{
UINT status ;
if ((dhcp_ptr == NX_NULL) || (server_address == NX_NULL))
{
return NX_PTR_ERROR;
}
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
status = _nx_dhcp_server_address_get(dhcp_ptr, server_address);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_server_address_get PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function retrieves the DHCP Client's DHCP server IP address on */
/* the first DHCP enabled interface found. */
/* */
/* Note that the caller should only call this service when the Client */
/* is bound to an IP address from a DHCP server. See the */
/* nx_dhcp_state_change_notify for notification of state changes. */
/* */
/* If multiple interfaces are enabled for DHCP, use */
/* nx_dhcp_interface_server_address_get() to get the server IP address */
/* on a specified interface. */
/* */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP Client task */
/* server_address Pointer to DHCP server address*/
/* */
/* OUTPUT */
/* */
/* status Actual completion status */
/* NX_DHCP_NO_INTERFACES_ENABLED No interfaces enabled for DHCP*/
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_server_address_get Interface specific server IP */
/* address get service */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address)
{
UINT i;
UINT status;
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER);
/* Find the DHCP interface record. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check the interface record is valid. */
if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) &&
(dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND))
{
/* Get the server address of first valid record. */
status = _nx_dhcp_interface_server_address_get(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, server_address);
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
}
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DHCP_NO_INTERFACES_ENABLED);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_interface_server_address_get PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking for the DHCP server get */
/* service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP Client task */
/* iface_index Interface of the Server */
/* server_address Pointer to DHCP server address */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_server_address_get Actual get server IP address */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address)
{
UINT status;
if ((dhcp_ptr == NX_NULL) || (server_address == NX_NULL))
{
return NX_PTR_ERROR;
}
if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return NX_INVALID_INTERFACE;
}
/* Check for appropriate caller. */
NX_THREADS_ONLY_CALLER_CHECKING
/* Call the actual reinitialize service. */
status = _nx_dhcp_interface_server_address_get(dhcp_ptr, iface_index, server_address);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_server_address_get PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function retrieves the DHCP Client's DHCP server IP address on */
/* the specified interface. */
/* */
/* Note that the caller should only call this service when the Client */
/* is in the bound state. See nx_dhcp_state_change_notify for */
/* notification when the Client state changes. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP Client task */
/* iface_index Interface of the DHCP server */
/* server_address Pointer to DHCP server address */
/* */
/* OUTPUT */
/* */
/* status Actual completion status */
/* NX_DHCP_NOT_BOUND Client state not Bound */
/* */
/* CALLS */
/* */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* _nx_dhcp_interface_record_find Find record for the interface */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address)
{
UINT status;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Check the record state. */
if (interface_record -> nx_dhcp_state >= NX_DHCP_STATE_BOUND)
{
/* Set the server IP address from the DHCP Client instance. */
*server_address = interface_record -> nx_dhcp_server_ip;
status = NX_SUCCESS;
}
else
status = NX_DHCP_NOT_BOUND;
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return status;
}
#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_ip_conflict PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function notifies the DHCP instance that a conflict was */
/* detected by the NetX ARP receive packet handling routine. */
/* */
/* INPUT */
/* */
/* ip_ptr IP instance pointer */
/* iface_index IP Interface Index */
/* ip_address IP Address to bind to */
/* physical_msw Physical address MSW */
/* physical_lsw Physical address LSW */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* tx_event_flags_set Set event flags */
/* */
/* CALLED BY */
/* */
/* NetX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _nx_dhcp_ip_conflict(NX_IP *ip_ptr, UINT iface_index, ULONG ip_address, ULONG physical_msw, ULONG physical_lsw)
{
NX_PARAMETER_NOT_USED(ip_ptr);
NX_PARAMETER_NOT_USED(ip_address);
NX_PARAMETER_NOT_USED(physical_msw);
NX_PARAMETER_NOT_USED(physical_lsw);
/* Set the interface index. */
_nx_dhcp_created_ptr -> nx_dhcp_interface_conflict_flag |= (UINT)(1 << iface_index);
/* Set the address conflict event flag. */
tx_event_flags_set(&(_nx_dhcp_created_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_CONFLICT_EVENT, TX_OR);
}
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_set_interface_index PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function does error checking for the set interface index call. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* interface_index Interface the DHCP Client task*/
/* is associated with */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_set_interface_index Actual set interface index */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT interface_index)
{
UINT status;
/* Check for invalid pointer input. */
if (dhcp_ptr == NX_NULL)
{
return(NX_PTR_ERROR);
}
/* Check for invalid non pointer input. */
if (interface_index >= NX_MAX_PHYSICAL_INTERFACES)
{
return(NX_INVALID_INTERFACE);
}
/* Call the actual set DHCP Client interface service */
status = _nx_dhcp_set_interface_index(dhcp_ptr, interface_index);
/* Return completion status. */
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_set_interface_index PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function enables DHCP on the specified interface. This function*/
/* should be called before the DHCP Client is started. The intended use*/
/* of this function is for DHCP to run on only one interface. To enable*/
/* multiple interfaces for DHCP, use the nx_dhcp_interface_enable */
/* service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface to enable DHCP on */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_enable Enable DHCP on interface */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT iface_index)
{
UINT i;
UINT status;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER);
/* Invalidate all the interfaces enabled for DHCP. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Invalidate this interface. */
dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid = NX_FALSE;
/* Change the state. */
dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state = NX_DHCP_STATE_NOT_STARTED;
}
/* Enable DHCP on this interface. */
status = _nx_dhcp_interface_enable(dhcp_ptr, iface_index);
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_interface_record_find PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* Find the Client record that is assigned to the input interface */
/* index, and return a pointer to that record. The interface index must*/
/* match the interface index of the Client record, and the interface */
/* must be enabled for DHCP. If no matching records are found, an */
/* error status is returned, and the interface record pointer is NULL. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* interface_index Interface to find */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful completion */
/* NX_DHCP_INTERFACE_NOT_ENABLED No matching record found */
/* */
/* CALLS */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
static UINT _nx_dhcp_interface_record_find(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_INTERFACE_RECORD **interface_record)
{
UINT i;
/* Find which DHCP Client interface record is assigned the input interface. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if this record is valid. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_FALSE)
continue;
/* Check if the interface index matches. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index == iface_index)
{
/* Yes, we found the record. */
*interface_record = &dhcp_ptr -> nx_dhcp_interface_record[i];
/* Return. */
return (NX_SUCCESS);
}
}
/* No matching record found. */
return (NX_DHCP_INTERFACE_NOT_ENABLED);
}
#ifdef NX_DHCP_CLIENT_RESTORE_STATE
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_client_get_record PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the get DHCP Client record */
/* service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* client_record_ptr Pointer to memory to save */
/* Client record to */
/* */
/* OUTPUT */
/* */
/* NX_PTR_ERROR Invalid pointer input */
/* status Completion status from */
/* internal DHCP calls */
/* */
/* CALLS */
/* */
/* _nx_dhcp_client_create_record */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr)
{
UINT status;
if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL))
{
return NX_PTR_ERROR;
}
status = _nx_dhcp_client_get_record(dhcp_ptr, client_record_ptr);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_client_get_record PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function creates a DHCP Client record for restoring the Client */
/* state between power cycles or idle (sleep) mode. It copies the */
/* first DHCP enabled Client record found to the supplied client record*/
/* pointer. If DHCP is enabled on multiple interfaces, use */
/* nx_dhcp_client_interface_record_get to get a record of a specific */
/* interface. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* client_record_ptr Pointer to Client record */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_DHCP_NO_INTERFACES_ENABLED No DHCP interface enabled */
/* */
/* CALLS */
/* */
/* _nx_dhcp_client_interface_get_record Get record for specified index*/
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr)
{
UINT i;
UINT status;
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the DHCP interface record. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check if the interface record is valid. */
if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) &&
(dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND))
{
/* Find a record of the current state of the DHCP CLient. */
status = _nx_dhcp_client_interface_get_record(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, client_record_ptr);
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DHCP_NO_INTERFACES_ENABLED);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_client_interface_get_record PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the get DHCP Client */
/* interface record service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface index */
/* client_record_ptr Pointer to memory to save */
/* Client record to */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_client_interface_create_record */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr)
{
UINT status;
/* Check for invalid input pointers. */
if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL))
{
return NX_PTR_ERROR;
}
/* Check interface index. */
if (iface_index >= NX_DHCP_CLIENT_MAX_RECORDS)
{
return NX_INVALID_INTERFACE;
}
status = _nx_dhcp_client_interface_get_record(dhcp_ptr, iface_index, client_record_ptr);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_client_interface_get_record PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function creates a DHCP Client record for restoring the Client */
/* state between power cycles or idle (sleep) mode. It then copies the*/
/* Client record to the supplied client record pointer. */
/* */
/* The DHCP Client state should be restored from a Client record saved */
/* to memory (client_record_ptr). */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface index */
/* client_record_ptr Pointer to memory to save */
/* Client record to */
/* */
/* OUTPUT */
/* */
/* NX_DHCP_NOT_BOUND Client not Bound to address */
/* status Actual completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_interface_record_find Find interface record matching*/
/* the input interface */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr)
{
UINT status;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Check the state. */
if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND)
{
/* The DHCP Client is not bound to an IP address. Cannot create a record for restoring Client
state if the Client not bound to an IP address. */
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return NX_DHCP_NOT_BOUND;
}
/* Clear memory before filling with data. */
memset(client_record_ptr, 0, sizeof(NX_DHCP_CLIENT_RECORD));
/* Set the record. */
client_record_ptr -> nx_dhcp_state = interface_record -> nx_dhcp_state;
client_record_ptr -> nx_dhcp_ip_address = interface_record -> nx_dhcp_ip_address; /* Server assigned IP Address */
client_record_ptr -> nx_dhcp_network_mask = interface_record -> nx_dhcp_network_mask; /* Server assigned network mask */
client_record_ptr -> nx_dhcp_gateway_address = interface_record -> nx_dhcp_gateway_address;
client_record_ptr -> nx_dhcp_server_ip = interface_record -> nx_dhcp_server_ip;
client_record_ptr -> nx_dhcp_timeout = interface_record -> nx_dhcp_timeout;
client_record_ptr -> nx_dhcp_lease_time = interface_record -> nx_dhcp_lease_time ;
client_record_ptr -> nx_dhcp_renewal_time = interface_record -> nx_dhcp_renewal_time;
client_record_ptr -> nx_dhcp_rebind_time = interface_record -> nx_dhcp_rebind_time;
client_record_ptr -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_renewal_remain_time;
client_record_ptr -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_rebind_remain_time;
client_record_ptr -> nx_dhcp_interface_index = interface_record -> nx_dhcp_interface_index;
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_client_restore_record PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the client restore service.*/
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* client_record_ptr Pointer to previously saved */
/* Client record */
/* time_elapsed Time elapsed in timer ticks */
/* */
/* OUTPUT */
/* */
/* NX_PTR_ERRPR Invalid pointer input */
/* status NetX completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_client_restore_record Actual restore record service */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed)
{
UINT status;
if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL))
{
return NX_PTR_ERROR;
}
/* Note: zero time elapsed is an acceptable value. */
status = _nx_dhcp_client_restore_record(dhcp_ptr, client_record_ptr, time_elapsed);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_client_restore_record PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function updates the DHCP Client state of the first DHCP */
/* enabled interface found with the supplied DHCP Client record */
/* pointed to by the client_record_ptr pointer. It then updates the */
/* time out parameters of the DHCP Client with the time_elapsed */
/* input (in timer ticks). */
/* */
/* If DHCP is enabled on multiple interfaces, use */
/* nx_dhcp_client_interface_restore_record to restore a record to a */
/* specific interface. */
/* */
/* This function is intended for restoring Client state between reboots*/
/* and assumes the DHCP Client state was previously obtained and stored*/
/* in non volatile memory before power down. */
/* */
/* Note: his should not be called in addition to _nx_dhcp_client_update*/
/* _time_remaining. _nx_dhcp_client_restore_ calls that function, */
/* so calling t_nx_dhcp_client_update_time_remaining separately would */
/* effectively apply the time elapsed a second time. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* client_record_ptr Pointer to previously saved */
/* Client record */
/* time_elapsed time input in timer ticks */
/* */
/* OUTPUT */
/* */
/* NX_DHCP_NO_INTERFACES_ENABLED No interfaces enabled for DHCP*/
/* status NetX completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_client_interface_restore_record */
/* Interface specific restore */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed)
{
UINT i;
UINT status;
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the DHCP interface record. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check which interface record is valid. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid)
{
/* Create a record of the current state of the DHCP Client. */
status = _nx_dhcp_client_interface_restore_record(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index,
client_record_ptr, time_elapsed);
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DHCP_NO_INTERFACES_ENABLED);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_client_interface_restore_record PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the client restore service.*/
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* iface_index Interface index */
/* client_record_ptr Pointer to previously saved */
/* Client record */
/* time_elapsed time input in timer ticks */
/* */
/* OUTPUT */
/* */
/* NX_PTR_ERRPR Invalid pointer input */
/* status NetX completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_client_interface_restore_record */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed)
{
UINT status;
/* Check for invalid input pointers. */
if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL))
{
return NX_PTR_ERROR;
}
/* Check interface index. */
if (iface_index >= NX_DHCP_CLIENT_MAX_RECORDS)
{
return NX_INVALID_INTERFACE;
}
status = _nx_dhcp_client_interface_restore_record(dhcp_ptr, iface_index, client_record_ptr, time_elapsed);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_client_interface_restore_record PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function updates the DHCP Client state with the input DHCP */
/* Client record for the specified interface. It copies data from the */
/* Client record to the interface racord, and updates the time out */
/* parameters of the DHCP Client with the time_elapsed inpur (in timer */
/* ticks). */
/* */
/* This function is intended for restoring Client state between reboots*/
/* and assumes the DHCP Client record was previously obtained and */
/* stored in non volatile memory before power down. */
/* */
/* Note: this should not be called in addition to */
/* nx_dhcp_client_update_time_remaining. */
/* nx_dhcp_client_interface_restore_record calls that function, so */
/* calling nx_dhcp_client_update_time_remaining would apply the time */
/* elapsed a second time. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* client_record_ptr Pointer to previously saved */
/* Client record */
/* time_elapsed time input in timer ticks */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful completion status */
/* status NetX completion status */
/* */
/* CALLS */
/* */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* _nx_dhcp_interface_record_find Find client record for */
/* specified interface */
/* nx_ip_interface_address_set Set IP interface address */
/* _nx_dhcp_client_update_time_remaining Update time remaining for time*/
/* elapsed while powered down */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), and */
/* restored the gateway */
/* address, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed)
{
UINT status;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
interface_record -> nx_dhcp_state = client_record_ptr -> nx_dhcp_state;
interface_record -> nx_dhcp_gateway_address = client_record_ptr -> nx_dhcp_gateway_address;
interface_record -> nx_dhcp_server_ip = client_record_ptr -> nx_dhcp_server_ip;
interface_record -> nx_dhcp_timeout = client_record_ptr -> nx_dhcp_timeout;
interface_record -> nx_dhcp_lease_time = client_record_ptr -> nx_dhcp_lease_time ;
interface_record -> nx_dhcp_renewal_time = client_record_ptr -> nx_dhcp_renewal_time;
interface_record -> nx_dhcp_rebind_time = client_record_ptr -> nx_dhcp_rebind_time;
interface_record -> nx_dhcp_renewal_remain_time = client_record_ptr -> nx_dhcp_renewal_remain_time;
interface_record -> nx_dhcp_rebind_remain_time = client_record_ptr -> nx_dhcp_rebind_remain_time;
/* Restore directly from the client record. */
interface_record -> nx_dhcp_ip_address = client_record_ptr -> nx_dhcp_ip_address;
interface_record -> nx_dhcp_network_mask = client_record_ptr -> nx_dhcp_network_mask;
interface_record -> nx_dhcp_interface_index = iface_index;
/* Update the IP instance with saved network parameters.*/
status = nx_ip_interface_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, iface_index, interface_record -> nx_dhcp_ip_address, interface_record -> nx_dhcp_network_mask);
/* Check status. */
if (status != NX_SUCCESS)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return status;
}
/* Check if the gateway address is valid. */
if (interface_record -> nx_dhcp_gateway_address)
{
/* Set the gateway address. */
status = nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address);
/* Check status. */
if (status != NX_SUCCESS)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
}
/* Now apply the time elapsed to update the DHCP Client time remaining on its lease and current DHCP state. */
status = _nx_dhcp_client_interface_update_time_remaining(dhcp_ptr, interface_record-> nx_dhcp_interface_index, time_elapsed);
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr->nx_dhcp_mutex));
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_client_update_time_remaining PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the update time remaining */
/* service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* time_elapsed time input in timer ticks */
/* */
/* OUTPUT */
/* */
/* status Actual Completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_client_update_time_remaining Update DHCP timeout for time */
/* elapsed while powered down */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return NX_PTR_ERROR;
}
status = _nx_dhcp_client_update_time_remaining(dhcp_ptr, time_elapsed);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_client_update_time_remaining PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function applies the input time_elapsed to the DHCP Client */
/* time remaining and determines if a state change occurred meanwhile. */
/* Note that time_elapsed is in timer ticks. */
/* */
/* There is no need to call this function if also calling */
/* _nx_dhcp_client_restore_record which applies the elapsed time. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* time_elapsed time input in timer ticks */
/* */
/* OUTPUT */
/* */
/* status Actual completion status */
/* NX_DHCP_NO_INTERFACES_ENABLED No interface enabled for DHCP */
/* */
/* CALLS */
/* */
/* _nx_dhcp_client_interface_update_time_remaining */
/* Apply the elapsed time to the */
/* specified DHCP timeout */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* */
/* CALLED BY */
/* */
/* _nx_dhcp_client_restore_record */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed)
{
UINT i;
UINT status;
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the DHCP interface record. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check which interface record is valid. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid)
{
/* Create a record of the current state of the DHCP CLient. */
status = _nx_dhcp_client_interface_update_time_remaining(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, time_elapsed);
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(NX_DHCP_NO_INTERFACES_ENABLED);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_client_interface_update_time_remaining PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking on the update time remaining */
/* service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* time_elapsed time input in timer ticks */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* NX_PTR_ERROR Invalid pointer input */
/* NX_INVALID_INTERFACE Invalid interface index */
/* */
/* CALLS */
/* */
/* _nx_dhcp_client_interface_update_time_remaining */
/* Actual update time service */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed)
{
UINT status;
/* Check for invalid input pointers. */
if (dhcp_ptr == NX_NULL)
{
return NX_PTR_ERROR;
}
/* Check interface index. */
if (iface_index >= NX_DHCP_CLIENT_MAX_RECORDS)
{
return NX_INVALID_INTERFACE;
}
status = _nx_dhcp_client_interface_update_time_remaining(dhcp_ptr, iface_index, time_elapsed);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_client_interface_update_time_remaining PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function applies the input time_elapsed data to the DHCP Client*/
/* state and determines what state it should be in (e.g. BOUND, */
/* IP address. Note, time_elapsed is in timer ticks. If called from the*/
/* application it is assumed the application device is sleeping, not */
/* powering up. If the device is waking up from sleeping, it does not */
/* need to restore the DHCP client state but only to update the time */
/* elapsed. */
/* */
/* Therefore this should not be called in addition to */
/* _nx_dhcp_client_restore_record. The restore record service handles */
/* updating time remaining, such that calling this service would */
/* effectively apply the time elapsed a second time. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* time_elapsed time input in timer ticks */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful Completion status */
/* status Actual completion status */
/* */
/* CALLS */
/* */
/* tx_mutex_get Obtain protection mutex */
/* tx_mutex_put Release protection mutex */
/* _nx_dhcp_update_renewal_timeout Update time remaining on lease*/
/* _nx_dhcp_interface_record_find Find record for the interface */
/* _nx_dhcp_interface_reinitialize Clear DHCP and IP network */
/* parameters */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed)
{
UINT status;
UINT accrued_time_adjusted = 0;
UINT time_accrued;
UINT original_state;
NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL;
/* Obtain DHCP Client protection mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Find the interface record. */
status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record);
/* Check status. */
if (status)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Get the original state. */
original_state = interface_record -> nx_dhcp_state;
/* Compute the time since the lease was assigned before we suspended the Client. */
if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_BOUND)
{
if (interface_record -> nx_dhcp_renewal_time >= interface_record -> nx_dhcp_timeout)
{
/* Since the Client is in a BOUND state, we know the timeout is less than T2
or nx_dhcp_renew_time. */
time_accrued = interface_record -> nx_dhcp_renewal_time - interface_record -> nx_dhcp_timeout;
}
else
{
/* Invalid DHCP timeout. If it is in the BOUND state, set to the renewal time. */
time_accrued = interface_record -> nx_dhcp_renewal_time;
}
}
else if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING)
{
/* Since the Client is in the RENEWING state, the total time on the lease is the
lease rebind time - the time out in the RENEW state: */
time_accrued = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_remain_time;
/* Note if dhcp_ptr -> nx_dhcp_rebind_time < dhcp_ptr -> nx_dhcp_renewal_remain_time,
the CLient either received invalid DHCP parameters or there is an internal error.
The renewal time should never exceed the rebind time. */
}
else if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING)
{
/* Since the Client is in the REBINDING state, the total time on the lease is the
lease time - the time remaining in the REBIND state: */
time_accrued = interface_record -> nx_dhcp_lease_time - interface_record -> nx_dhcp_rebind_remain_time;
/* Note if dhcp_ptr -> nx_dhcp_lease_time < dhcp_ptr -> nx_dhcp_rebind_remain_time,
the CLient either received invalid DHCP parameters or there is an internal error.
The rebind time should never exceed the lease time. */
}
else
{
/* Expired! */
accrued_time_adjusted = 0xFFFFFFFF;
}
/* Adjust the time accrued to include the interval while the Client was suspended. */
if (accrued_time_adjusted != 0xFFFFFFFF)
{
accrued_time_adjusted = time_accrued + time_elapsed;
}
/* Determine if the DHCP Client needs to renew. */
if (accrued_time_adjusted < interface_record -> nx_dhcp_renewal_time)
{
/* Not yet. Update the nx_dhcp_timeout for the time elapsed and we're done. */
interface_record -> nx_dhcp_timeout -= time_elapsed;
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* We are done. Ok to resume the Client. */
return NX_SUCCESS;
}
/* Determine if the Client should renew. */
else if (accrued_time_adjusted < interface_record -> nx_dhcp_rebind_time)
{
/* Yes; it has not reached the expiration on the renew period. */
/* Check if it is already in the RENEW state. */
if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING)
{
/* Yes it is, so do nothing. Let the Client continue renewing. */
/* Update the time remaining for the Client to renew its lease. */
interface_record -> nx_dhcp_renewal_remain_time -= time_elapsed;
/* Reset the timeout based on the updated time remaining to renew. */
interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time);
/* Record the retransmission interval. */
interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout;
}
else
{
/* No it wasn't so update the Client for the RENEW state. */
/* Compute how many seconds into the renew period the Client is (total time on lease over and above
the time to start renewing. */
if (accrued_time_adjusted == interface_record -> nx_dhcp_renewal_time)
{
interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_time;
}
else
{
interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - accrued_time_adjusted;
}
/* Set the DHCP timeout for being in the RENEW phase. */
interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time);
/* Record the retransmission interval. */
interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout;
/* And change to the Renewing state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_RENEWING;
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* We are done. Ok to resume the Client. */
return NX_SUCCESS;
}
/* Determine if it is time for the Client to rebind (e.g. check the lease has not completely expired). */
else if (accrued_time_adjusted < interface_record -> nx_dhcp_lease_time)
{
/* Check if it is already in the REBIND state. */
if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING)
{
/* Yes it is, so do nothing. Let the Client complete its rebind task*/
/* Update the time remaining for the Client to rebind an IP address. */
interface_record -> nx_dhcp_rebind_remain_time -= time_elapsed;
/* Reset the timeout based on the updated time remaining to rebind. */
interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time);
/* Record the retransmission interval. */
interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout;
}
else
{
/* No it wasn't so update the Client for the REBIND state. */
/* Compute how many seconds into the rebind period the Client is (total time on lease over and above
the time to start rebinding. */
if (accrued_time_adjusted == interface_record -> nx_dhcp_rebind_time)
{
interface_record -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_lease_time - interface_record -> nx_dhcp_rebind_time;
}
else
{
interface_record -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_lease_time - accrued_time_adjusted;
}
/* Set the DHCP timeout for being in the RENEW phase. */
interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time);
/* Record the retransmission interval. */
interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout;
/* Record the retransmission interval. */
interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout;
/* And change to the Rebinding state. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_REBINDING;
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* We are done. Ok to resume the Client. */
return NX_SUCCESS;
}
else
{
/* Clear the existing DHCP Client network parameters for restarting in the INIT state. */
_nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index);
/* Start the DHCP protocol again by setting the state back to INIT. */
interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT;
/* The client begins in INIT state and forms a DHCPDISCOVER message.
The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup.
RFC2131, Section4.4.1, Page36. */
/* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */
interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE;
interface_record -> nx_dhcp_rtr_interval = 0;
}
/* Check if the state is changed. */
if (original_state != interface_record -> nx_dhcp_state)
{
/* Determine if the application has specified a routine for DHCP state change notification. */
if (dhcp_ptr -> nx_dhcp_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state);
}
/* Determine if the application has specified a routine for DHCP interface state change notification. */
if (dhcp_ptr -> nx_dhcp_interface_state_change_callback)
{
/* Yes, call the application's state change notify function with the new state. */
(dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state);
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr->nx_dhcp_mutex));
return NX_SUCCESS;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_resume PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking for the Client resume service.*/
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* NX_PTR_ERROR Invalid pointer input */
/* status Actual completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_resume Actual Client resume service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_resume(NX_DHCP *dhcp_ptr)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return NX_PTR_ERROR;
}
status = _nx_dhcp_resume(dhcp_ptr);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_resume PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function resumes the DHCP Client thread and timer. It then */
/* checks the state on all DHCP enabled interfaces if renewing or */
/* rebinding. If so it sends a REQUEST to the DHCP server. */
/* */
/* The DHCP Client application can then call the */
/* nx_dhcp_client_udpate_remaining_time() service to update the time */
/* remaining on the client lease, before calling nx_dhcp_resume. */
/* */
/* This function does not change the Client state, lease timeout or */
/* time remaining on the current lease. It requires the */
/* NX_DHCP_CLIENT_RESTORE_STATE option to be enabled. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful Completion status */
/* NX_DHCP_ALREADY_STARTED DHCP Client thread started */
/* status NetX or ThreadX completion */
/* status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_send_request_internal Send message to DHCP server */
/* nx_udp_socket_bind Bind UDP socket to port */
/* tx_thread_resume Resume the DHCP Client thread */
/* tx_mutex_get Obtain mutex protection */
/* tx_mutex_put Release mutex protectiob */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), and */
/* fixed compiler warnings, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_resume(NX_DHCP *dhcp_ptr)
{
UINT i;
UINT status;
NX_IP *ip_ptr;
ULONG client_physical_msw;
ULONG client_physical_lsw;
UINT iface_index;
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Resume the DHCP processing thread. */
status = tx_thread_resume(&(dhcp_ptr -> nx_dhcp_thread));
/* Determine if the resume was successful. */
if ((status != TX_SUCCESS) && (status != TX_SUSPEND_LIFTED))
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Active the timer. */
status = tx_timer_activate(&(dhcp_ptr -> nx_dhcp_timer));
/* Check status. */
if (status)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Bind the UDP socket to the DHCP Client port. */
status = nx_udp_socket_bind(&(dhcp_ptr -> nx_dhcp_socket), NX_DHCP_CLIENT_UDP_PORT, NX_WAIT_FOREVER);
/* Check status. */
if (status)
{
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
return(status);
}
/* Set IP pointer. */
ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr;
/* Loop to process interface records. */
for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++)
{
/* Check which interface record is valid. */
if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid)
{
/* Get the interface index. */
iface_index = dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index;
/* Get the client MAC address from the device interface. */
client_physical_msw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw;
client_physical_lsw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw;
/* Generate a 'unique' client transaction ID from the MAC address for each message to the server. */
dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_xid = client_physical_msw ^ client_physical_lsw ^ (ULONG)NX_RAND();
/* If the DHCP Client is renewing or rebinding on being resumed, send a DHCP request. */
if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state == NX_DHCP_STATE_RENEWING) ||
(dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state == NX_DHCP_STATE_REBINDING))
{
/* Transmit the request message. */
_nx_dhcp_send_request_internal(dhcp_ptr, &dhcp_ptr -> nx_dhcp_interface_record[i], NX_DHCP_TYPE_DHCPREQUEST);
}
}
}
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return completion status. */
return(NX_SUCCESS);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nxe_dhcp_suspend PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs error checking for the Client suspend */
/* service. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful Completion status */
/* status Actual completion status */
/* */
/* CALLS */
/* */
/* _nx_dhcp_suspend Actual Client suspend service */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nxe_dhcp_suspend(NX_DHCP *dhcp_ptr)
{
UINT status;
if (dhcp_ptr == NX_NULL)
{
return NX_PTR_ERROR;
}
status = _nx_dhcp_suspend(dhcp_ptr);
return status;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_dhcp_suspend PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function suspends the DHCP Client task thread and unbinds the */
/* socket port. The intented use of this service is to combine with the*/
/* resume service such that the calling application can 'pause' the */
/* DHCP Client for a certain amount of time, and resume it in the same */
/* state. The DHCP Client application can then call the */
/* nx_dhcp_client_udpate_remaining_time service to update the time */
/* remaining on the client lease, then nx_dhcp_resume to actually */
/* resume the DHCP Client task. */
/* */
/* This function does not change the Client state, lease timeout or */
/* time remaining on the current lease. It requires the */
/* NX_DHCP_CLIENT_RESTORE_STATE option to be enabled. */
/* */
/* INPUT */
/* */
/* dhcp_ptr Pointer to DHCP instance */
/* */
/* OUTPUT */
/* */
/* NX_SUCCESS Successful Completion status */
/* */
/* CALLS */
/* */
/* nx_udp_socket_unbind Unbind port from UDP socket */
/* tx_timer_deactivate Stop the timer */
/* tx_thread_suspend Suspend the DHCP Client thread*/
/* tx_mutex_get Obtain mutex protection */
/* tx_mutex_put Release mutex protection */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _nx_dhcp_suspend(NX_DHCP *dhcp_ptr)
{
/* Get the DHCP mutex. */
tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);
/* Suspend the DHCP thread. */
tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread));
/* Deactive the timer. */
tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer));
/* Unbind the port. */
nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket));
/* Release the DHCP mutex. */
tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex));
/* Return completion status. */
return(NX_SUCCESS);
}
#endif /* NX_DHCP_CLIENT_RESTORE_STATE */